1
votes

I am new to Ionic 3 & Angular and ran into an issue with *ngFor and .subscribe() method. Please forgive me if it is an easy question. I tried to figure out the behaviour of http.get(..).map(..).subscribe() function when used along with *ngFor to maintain an array of objects and show the records to user using *ngFor on the .html template file but unable to know *ngFor's odd behaviour.

In my Ionic 3 App, I am getting the data using an API and storing it inside a component variable called "users" which is declared as below in component .ts file -

users: Array<any>;

I have below component function which gives me data for this users array -

addUser(count: number) {
  this.http.get('https://randomuser.me/api/?results=' + count)
  .map(data => data.json().results)
  .subscribe(result => {
    for (let val of result) {
      this.users.push(val);
    }
  })
}

Initially, I get data for 10 users from the API using above component function by simply calling it inside my ngAfterViewInit() function like -

this.addUser(10); 

This gives me 10 user record objects inside my users array which I show to the user using something like below in the view .html file -

<ion-card *ngFor="let user of users">
  {{user.email}}
</ion-card>

At this time *ngFor puts the last array element at first in the view and shows the records in the descending order as the elements in the array starting from index 9 to 0.(LIFO order)

Now I start popping the last element from this users array using users.pop(); and push another element at the beginning at index 0 by shifting current elements using users.unshift(..) in below function and calling it as addNewUser(1); -

addNewUser(count: number) {
      this.http.get('https://randomuser.me/api/?results=' + count)
      .map(data => data.json().results)
      .subscribe(result => {
        for (let val of result) {
          this.users.unshift(val);
        }
      })
    }

At this moment, if we consider the first array which had 10 elements, the last object at index 9 had been removed and another element at index 0 has been added making the previous elements on index 0-8 to shift to index 1-9.

On doing so, my view gets updated which has *ngFor and surprisingly this time it shows the first element at first place which is actually on index 0 which is the one I recently put. This is opposite to the order earlier followed by *ngFor to render elements on the screen.

Why *ngFor in Ionic 3 view shows the recently inserted object element first from the array of objects which is dependent on the subscribe method .subscribe() method. I am really confused about this.

I really need to clear the concept of *ngFor and subscribe(). Please help me.

Note : The API mentioned above is publicly accessible for testing and you may call it to check the response structure if required. Pasting a sample API response below on calling https://randomuser.me/api/?results=1 -

{
    "results": [
        {
            "gender": "male",
            "name": {
                "title": "mr",
                "first": "daniel",
                "last": "stoll"
            },
            "location": {
                "street": "9719 tannenweg",
                "city": "cottbus/chosebuz",
                "state": "bremen",
                "postcode": 81443
            },
            "email": "[email protected]",
            "login": {
                "username": "greenleopard994",
                "password": "chat",
                "salt": "OUjisBdQ",
                "md5": "8148d51998f3fef835a5f3979218c181",
                "sha1": "131ae09d045b345efe36a330bf17a450b76f7de3",
                "sha256": "94c3a362b5f516d0fb1d4e9dbb632d32d57b8886d5cc7bf0d5cedc99e7d55219"
            },
            "dob": "1957-04-26 22:07:14",
            "registered": "2002-04-29 10:57:34",
            "phone": "0556-4348870",
            "cell": "0172-5116200",
            "id": {
                "name": "",
                "value": null
            },
            "picture": {
                "large": "https://randomuser.me/api/portraits/men/14.jpg",
                "medium": "https://randomuser.me/api/portraits/med/men/14.jpg",
                "thumbnail": "https://randomuser.me/api/portraits/thumb/men/14.jpg"
            },
            "nat": "DE"
        }
    ],
    "info": {
        "seed": "8fd4afe85884c767",
        "results": 1,
        "page": 1,
        "version": "1.1"
    }
}

Refer this example showing my issue.

2
can you please share your api response as well with question ? means json of result variable ?Babar Bilal
btw don't update the users variable because it will hurt the change detection of angular create a local variable assign all users in it then assign it into users variable.Babar Bilal
@BabarBilal I have added the API response above. This API is publicly accessible and you may also call it to see the response structure. I am confused on the behavior of *ngFor. First time it is showing the last element of the array on the view and second time on adding element at the beginning of the array it is showing the first array element in the view.gauravparmar
At this time *ngFor puts the last array element at first in the view: no, it doesn't. See stackblitz.com/edit/angular-q1kdfh?file=app%2Fapp.component.ts. Post a complete minimal example reproducing your issue.JB Nizet
@BabarBilal Here is the basic example showing my issue - stackblitz.com/edit/angular-ijzrss?file=app%2Fapp.component.ts . I am using angular2-swing library to show users on swipeable cards and swipe left or right on the cards to get next card below it. In this example you will find that when you start swiping the card left or right, you see the name on the card below it and on totally swiping the card left or right the recently added card comes on the top instead of the old second card. Open the console while seeing my shared example in which I am monitoring the state of array.gauravparmar

2 Answers

0
votes

If you have a sorting issue with indexing and you think it's related.. you could work around the issue by assigning an index:

*ngFor="let user of users; let i = index"

and then reference the direct index value

users[i]
0
votes

You should make a copy of that array. Editing array elements while looping them can lead to unexpected behaviour.