API Data Not Refreshing With New HTTP/Fetch call


#1

Hi. I have the following issue in Nativescript Angular:

I call data from an API (using fetch) and display the data in a view. After I leave the page, if I then return to it, the original data is still there on the page, and the new data is called again, so the data is showing twice (or more if you do this more). The original data should not be there, but for some reason is sticking around in the view.

For example, say when I go to a certain page I load the following data on the page:
Red, Blue, Yellow

If I leave the page, but then later return to it, the original data is still there, and new data is also loaded, so the page will say:
'Red, Red, Blue, Blue, Yellow, Yellow'

and so on. This happens despite the fact that the data is supposed to be called fresh with each time the page loads.

Has anyone found a solution for this, so that the original data is removed from the page?

This may be an issue more so with Angular itself.

I have tried different methods of trying to clear the data array, to no avail.

Here is example code: each time the page loads, the data is called again:

ts:

public colors: Array<any> = [];

getAPI(){
    var token = TOKEN
    var url = URL
    return fetch(url, {
       method: "GET",
       headers: new Headers({'Authorization': 'Bearer ' + TOKEN})
     }).then((response) => {
          return response.json();}) 
          .then((returnedData) => { 
             this.returnedData.forEach((item)=>{ 
                  this.colors.push(item)
               })
       })
     }

html:

 <GridLayout>
      <RadListView [items]="colors">
          <ng-template tkListItemTemplate let-color="item" >
              <StackLayout>
                  <Label [text]="color"></Label>
              </StackLayout>
          </ng-template>
      </RadListView>
  </GridLayout>

#2

Did you try doing this.colors = [] inside the fetch response? Or slice the array as a first step?


#3

I have tried this.colors = [ ] , and that did not make a difference. By ‘slice’, do you mean to slice out the part of the array that is not refreshing? That would prob not work–or at least it would get pretty complicated as a workaround, as the non-refreshing part multiplies each time the page loads.

But in general, I assume this is more of a bug, or at least a quirk, that should not be happening.


#4

By the way, if I run things in the console, and register what is actually loaded when the page loads, things are correct–the API data just loads once each time the page loads. The issue I think is that the old data is sticking around in the view.


#5

Perhaps it’s best to throw this in the Playground at play.nativescript.org so others can see it and tinker with it.


#6

Thanks. Not sure I can put this in the playground. The data is fairly complex, and without the exact data it is probably not worth while to play around with the code itself.

I think the issue is more to do with default Angular behavior in rendering a view. In my app, I call api data in a few different spots, and this only happens in one spot, despite using almost identical code. The data itself is similar in these different spots, except that in some views images are displayed. So the app does not do it across the board.

Just in some circumstances the old view is never removed when a page is reloaded. I can see this because it takes a moment for the new api data to appear, and during the time it is loading you can see the old page sitting there. When the new data then does load, it is added to the old view.

It sounds similar to the bug reported for Angular regarding BrowserAnimations: https://github.com/angular/angular/issues/19093
https://stackoverflow.com/questions/45622453/angular2-router-appends-component-instead-of-replacing-it

But I don’t think that is quite it here, given that I don’t find BrowserAnimations in use in my app.


#7

Is there a way to force a reload of a page in Nativescript?

(can’t seem to get window.location.reload() to work, which would make sense given that this is xml. Maybe there is a comparable tool I can use in Nativescript?)


#8

I am still not sure why the view is not getting cleared out on load…but I do have a working solution. @Eddy, it is the slice() method you mentioned, which is referenced by eduardoturconi here: https://github.com/NativeScript/nativescript-angular/issues/377 . Thank you for the suggestion.

Here is example code that works for me on the ios simulator (where I had the trouble before). The slice() method does not work for me unless the slice() action is placed in a particular spot, such as right before repopulating the array that houses the data:

public colors: Array<any> = [];

getAPI(){
    var token = TOKEN
    var url = URL
    return fetch(url, {
       method: "GET",
       headers: new Headers({'Authorization': 'Bearer ' + TOKEN})
     }).then((response) => {
          return response.json();}) 
          .then((returnedData) => { 
             this.colors = this.colors.slice() /*********Here is the slice method that stops the data from being shown on top of the old populated data********/
             this.returnedData.forEach((item)=>{ 
                  this.colors.push(item)
               })
       })
     }

#9

Note: The solution I posted above does work for me to get around the problem, but it would still be helpful to know if others know why the problem occurs in the first place.

Issue summary: load api data to populate a page, leave the page, and then when you return to the page the populated data from before is still there (so that, without a workaround, the new api data that gets called on the load of that page appears in addition to the old). In other words, the old view gets “stuck” on the page.


#10

What do you mean by old view gets stuck on page? The new data never updated on screen but still shows old data, if Yes then the reason is obvious that Angular would not come to know that you have changed the data as it runs in a promise. Use http client apis or force change detection once your api finishes. Or use a subject to hold data so Angular detects the change and updates your UI.


#11

Thanks. I have tried change detection and that did not make a difference. Angular is able to know I have changed the data–because the data is updated on the page (and if I track the data on the console, it is updated properly). But the view itself still maintains the old data as well. Example is like above:
Say I have an api with the following data, that I call with fetch upon visiting a page:
Red, Blue, Yellow

When I go to the page, it shows:
Red, Blue, Yellow

If I then leave the page, and then return to it, the page shows:
Red, Red, Blue, Blue, Yellow, Yellow

Because the old data (the old colors) are still there, and the new data is loaded on top of it. So the fetch function is working properly–loading the updated data when the page loads, but the view is malfunctioning, keeping the old view as a baseline and then taking the new data on top of it. Doing things like change detection or clearing out the array did not make a difference. For some reason, the slice method noted above did properly clear out the page.


#12

Angular is just rendering the data according to the contents of the array ‘colors’. Your are pushing new items to the array on every fetch, and that is the source of the duplication.

Maybe you just need to recreate the array on your promise:

this.colors = returnedData

Clearing the array or calling slice() will also do the trick, but is usually beter to treat all data as immutable.