Angular ngFor not iterating through array on Android

Hello all,
First post, and pretty new user of ionic. So far I love it! My web app is working just dandy, but I’m running into an issue with android (haven’t gotten to iOS yet). I scoured the internet from corner to corner and couldn’t figure it out.

Here’s the rundown:
Retrieving an array of objects from my data api. The logs show everything to be returning as it should. I begin to have issues when trying to use an ngFor on either an ion-col (this is what I’m using for web) and even an ion-list. Basically android debugging is saying Error trying to diff, and that my array isn’t iterable. Here’s some code to see what’s going on.

page.ts file:

selection: Array<SelectionModel>=[];

getSelection() {
    if (this.platform.is('ios') || this.platform.is('android') || this.platform.is('mobile')) {
      this.httpMobile.get('https://www.asdf.com/' + this.config.endpoints.getSelection, {}, {})
        .then(data => {
          this.selection = data.data;
          console.log('selection: ' + this.selection);
          console.log(data.status);
          console.log(data.data); // data received by server
          console.log(data.headers);

        })
        .catch(error => {
          console.log(error.status);
          console.log(error.error); // error message as string
          console.log(error.headers);

        });
    } else {
      this.selectionService.getSelections('web').subscribe(
        x => {
          this.selection = x;
        },
        error => {
          console.log(error);
        },
        () => {
          // this.loadingScreen = false;
        }
      );
    }

html file:

<div *ngIf="ios || android">
        <ion-list *ngFor="let item of selection; index as i">
          test
          {{item.name}}
        </ion-list>

data returned from api:

[
	{
		"name": "Grey Goose",
		"description": "This is a description but short.",
		"size": "750ml",
		"price": 29.99,
		"content": 40,
		"brand": "Grey Goose",
		"country": "France",
		"state": null,
		"region": null,
		"inStock": true,
		"imageURL": "assets/spirits/vodka/greygoose.png",
		"typeId": 2,
		"categoryId": 1,
		"id": 1,
		"created": "2021-08-10T02:29:20.59",
		"lastModified": "0001-01-01T00:00:00"
	},
	{
		"name": "Absolut",
		"description": "This is a description but long. This is a description but long. This is a description but long.",
		"size": "750ml",
		"price": 19.99,
		"content": 40,
		"brand": "Absolut Vodka",
		"country": "Unites States",
		"state": "California",
		"region": null,
		"inStock": true,
		"imageURL": "assets/spirits/vodka/absolut.png",
		"typeId": 2,
		"categoryId": 1,
		"id": 2,
		"created": "2021-08-10T02:29:20.593",
		"lastModified": "0001-01-01T00:00:00"
	}
]

error in android studio:

Msg: ERROR Error: Error trying to diff '[{"name":"Grey Goose", ..<refer above for actual data>... }] Only arrays and iterables are allowed

My understanding is that the array returned is iterable. Am I just missing something here? Any help is appreciated!

Before we get too far down this road, IMHO pages should not be interacting with the network, period. That should all be isolated to services. And it would be fantastic if even services didn’t have this sort of conditional twiddling.

Can you try rearchitecting things so that:

  • SelectionService.getSelections() takes no parameters, so that it works exactly the same regardless if it’s on mobile or not
  • Internally, SelectionService uses Angular’s HttpClient only - no arcane plugins
  • SelectionService never checks what platform it’s running on

Apologies, I should’ve stated this, but it was already architected that way. Selection service does the calls, and uses httpclient by default and passes no parameters.

The only reason you’re seeing what you’re seeing (http call in the page with conditionals and parameters) is because google (and my testing on an android device) lead me to believe httpclient on android couldn’t use my https api. So I hacked together a condition to use HTTP (ionic-native/http/ngx) in the component instead for quick testing, which actually worked in returning the data from the api. Originally it was saying it couldn’t connect due to https something something (I would need to go back and see exact error as I’m not at my pc right now).

What I can do is revert my changes to continue to use httpClient and show you the error I’m getting that it can’t connect to a secure connection once I’m back on my PC. But again almost all posts I’ve seen on the topic say to use HTTP for mobile devices instead of angular’s httpClient. Am I mistaken in believing this?

If I do need to use HTTP for mobile and httpClient for web, I could easily make two separate functions in the service that get called depending on platform as to avoid the conditional logic in the service. I guess the first thing to hit is, should the angular httpClient be able to work within android (and presumably iOS)?

I won’t say “mistaken”, but I for one have about as strong an opinion as possible that one should only ever use HttpClient. It’s got better type safety, you are ensured that you’re actually testing the mobile code path during development, there’s less boilerplate, and boring low-level bugs like the one you seem to be encountering are far less common.

The main reason you see people recommending using plugins for HTTP is because they are encountering CORS problems that they won’t fix on the server side (I’m hesitant to ever say “can’t” here, because one can always fix CORS server-side with a proxy). The only legitimate reason I know of for using native HTTP is SSL certificate pinning, which is a pretty obscure and rare case.

I think your time will end up being better spent trying to fix this than the problem you’re currently seeing.

Absolutely and positively yes.

Thank you for your responses, coming from developing solely on angular for the web for the past 2 years, I will say I’ve only ever used httpClient and NEVER had any issues. It’s surely my preference to keep using something that I’ve grown accustomed to so I’ll give this another go. I’m not as worried about the CORS part, and I think I’ve setup my servers SSL properly but we shall see when I get there :grin:. I would like to keep the thread open maybe another day incase somebody has any other insight on this if that’s ok. I’ll reply here with the actual error it’s giving me with httpClient should I not be able to figure it out this evening.

Alright so I went back to httpClient, and sure enough I just needed to fix some settings with CORS on my backend. Thank you for the insight and opinion! Appreciate the help mate!

1 Like

For the record, what I suspect was happening is that you (rightly) got used to HttpClient dealing with the tedium of JSON marshalling and unmarshalling for you. Native HTTP plugins don’t provide that service, so you were inadvertently trying to treat a JSON string representation as an unmarshalled object.

In any event, glad it’s working for you now.

1 Like