0
votes

I am getting a weird error. I'm using Angular and Firebase (Real time DB) in a project and even thou everything is rendering correctly, I'm getting errors on the log.

VM368 OpenIdeasComponent.ngfactory.js:20 ERROR TypeError: Cannot read property 'firstName' of undefined at Object.eval [as updateRenderer] (VM368 OpenIdeasComponent.ngfactory.js:36) at Object.debugUpdateRenderer [as updateRenderer] (VM346 vendor.js:57875) at checkAndUpdateView (VM346 vendor.js:57250) at callViewAction (VM346 vendor.js:57486) at execEmbeddedViewsAction (VM346 vendor.js:57449) at checkAndUpdateView (VM346 vendor.js:57246) at callViewAction (VM346 vendor.js:57486) at execComponentViewsAction (VM346 vendor.js:57428) at checkAndUpdateView (VM346 vendor.js:57251) at callViewAction (VM346 vendor.js:57486)

On the database, under the Features collection I have a reference for the author ID that belongs to another collection called users.

On my FeaturesModel constructor I have author?: AuthorModel to be as an optional parameter.

So, when I initiate my component, I use a forEach to fetch the author data from the users collection and assign that object to the feature object.

Here is the code:

ideas.ts

ngOnInit() {
        this.fService.getFullFeature().subscribe(
          data => {
            this.features = data;
            this.features.forEach( el => {
              this.fService.getAuthor(el.userID).subscribe(
                authorData => {
                  const a = {
                    id: authorData.id,
                    firstName: authorData.firstName,
                    lastName: authorData.lastName,
                    email: authorData.email
                  };
                  el.author = a;
                },
                (e) => { console.error(e); }
              );
            });
            console.log(this.features);
          }
        );
    }

html

<div class="container-fluid">
    <div style="padding: 100px 0">
        <div class="row">
            <div class="container">
                <h1 class="green header text-center">Feature Summary</h1>
            </div>
        </div>
        <div class="row">
            <div class="container">
                <div class="row row-space link-effect" *ngFor="let idea of features" [routerLink]="['display/' + idea.id]" href="#modal" data-toggle="modal" data-target="#modal">
                    <div class="col-7">
                        <span class="open-ideas">{{ idea.title }}</span>
                    </div>
                    <div class="col-3 d-xs-none">
                        {{ idea.author.firstName }} {{ idea.author.lastName }}
                    </div>
                    <div class="col-2 d-xs-none">
                        <fa name="thumbs-up"></fa>
                        {{ idea.votes }}
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

So, in theory, now I have a object that contains the author's information, on the HTML I'm adding {{ feature.author.firstName }}, which works BUT I'm getting this console error.

What am I missing?

Thank you!

1
can you add the Html snippet as well?Tiago Silva
@TiagoSilva for sure! There ya go! ThanksMrRobot
el.author has no correlation to idea.author that we can see. The error is correct.JWP

1 Answers

0
votes

Your subscriptions inside the forEach are not completed when {{ feature.author.firstName }} is rendered at the very begining. This is why you get the error but still see the variable display in HTML, because it is rendered after the subscription is complete, hence after the error message.

You should use await async in this case

async ngOnInit() {
    //created another promise
    const promise1 = await this.fService.getFullFeature().toPromise().then(
      async data => {
        this.features = data;
        this.features.forEach( el => {
          //you wait for the promise to complete in order for your code to move on
          //this might be slow if you have a lot of data in the this.features array
          const promise2 = await this.fService.getAuthor(el.userID).toPromise().then(
             authorData => {
              const a = {
                id: authorData.id,
                firstName: authorData.firstName,
                lastName: authorData.lastName,
                email: authorData.email
              };
              el.author = a;
            }
          ).catch((e) => { console.error(e); });
        });
        console.log(this.features);
      }
    );
}