My Array does not execute for or foreach

Hello, can someone help me with the following question?

I have declared a global Array in my component:

visitantes: Array<User>;

Then I populate this Array when I click on a button:

 finalizarVisitantes() {
    this.visitantes = this._userService.getVisitantesPorArray(this.org, this.batismo.membros);
    console.log('Batizandos', this.visitantes);
    console.log('Batizandos', this.visitantes.length);

    this.visitantes.forEach(item => {
      console.log('Item', item);
    });
}

On my page, the rendered items usually appear:

<ion-item *ngFor="let bt of visitantes">
        <ion-avatar slot="start">
            <img [src]="bt.photoURL">
          </ion-avatar>
      <ion-label>
        <h3>{{bt.displayName}}</h3>
        <p>
          {{bt.email}}
        </p>
      </ion-label>
    </ion-item>

But in my code I can not traverse the Array and in the console it gives different values.
The first console shows all visitors.
But in the second it gives zero lenght.
And do not even enter my forEach.

erro

Anyone have any idea what might be happening?

I woud say the function _userService.getVisitantesPorArray() woud take same time to execute.
But js wont wait and executes the other lines before the result comes back from the function.

Try to use async and await.

Please post the definition of getVisitantesPorArray.

    getVisitantesPorArray(org: Org, visitantes: string[]): Array<User> {
      const arr: Array<User> = [];
      for (const x of visitantes) {
        this.getVisitante(org, x).forEach(item => {
          if (item.email === x) { arr.push(item); }
        });
      }
      return arr;
    }

I tried, but it did not work. Would you have an example to show?

OK, there’s nothing overtly asynchronous in there, so what I would do is to make sure that visitantes is initialized at the point of declaration:

visitantes: Array<User> = [];

Yes, I already did this test. is an array of string and is passing the data correctly.

I’m not talking about the argument in the provider, but rather the array in the component. You say

That implies to me that until that button is clicked, the visitantes property in the component that you are trying to iterate across with forEach is undefined. That will throw an error during rendering that will mysteriously break virtually everything in your page. Always initialize all component properties referred to in templates.

I do not think I understand.
This array is within the method and is temporary.
It is being started in the method, filled with getVisitant and returned at the end.

I wouldn’t use the term “global” here:

…but what I think you mean is a controller property, aka:

export class Page {
  visitantes: Array<User>;
  ...
}

That’s the only way you could be using it in the associated template with forEach. “Temporary” or lexically-scoped variables are invisible to templates.

This is the visitantes that I’m suggesting initializing:

export class Page {
  visitantes: User[] = [];
  ...
}

Tb did this and did not solve.
That’s strange. In a line of code it renders the values and soon in the next line the same variable renders another without no other action.

What does this function?

returns an object visitante: <User>

And it is not asynchron too?

Ok and have you checked that
item.email === x
isn’t always false?

I changed now to:

 getVisitantesPorArray(org: Org, visitantes: string[]): User[] {
      const arr: User[] = [];
      for (const x of visitantes) {
        this.getVisitante(org, x).pipe(map(item => arr.push(item)));
      }
      return arr;
    }

And continues with the same problem.

sorry no more ideas on my side

<img src="giant-flashing-siren.gif">

You can’t pretend that asynchronous things are synchronous. getVisitantesPorArray cannot return Array<User>. I was under the impression that forEach was Array.forEach.

Now the entire discussion is radically different, and I don’t speak enough Portuguese to know what getVisitantesPorArray needs to be called, but it probably shouldn’t be that. See this post for some background.

needsProperName(org: Org, visitantes: string[]): Observable<User[]> {
  return from(visitantes).pipe(
    mergeMap(vn => this.getVisitante(org, vn)),
    toArray()
  );
}

Thanks for the personal help.
I found a library called RxFire.
I used the combinedLatest design with it, and I was able to do the merge of objects.
So, I no longer have to generate an Array.

Your suggestion @rapropos has opened this window.

Glad you found something that worked for you, and thanks for reporting back so that others in your situation might benefit.

1 Like