skip to Main Content

I am having trouble creating an ngIf statement in Angular. I am trying to show a div only when it would match a certain condition… but I keep getting this errorr in the browser console:

Cannot read properties of undefined (reading ‘0’)

What am I doing wrong?

My HTML is:

<div *ngIf="preSelectedPaymentOption[0].value === 3 && totalCartPrice > 380" class="payment-warning">
   <ion-label>
    <h3>Atention!</h3>
    <p>Lorem ipsum dolor sit!!!.</p>
  </ion-label>
</div>

This is how the data from the API looks like:
Api data console.log

And here is the TS code how I’m getting the data:

  getPaymentOptions() {
    this.cartService.getPaymenyOptions().subscribe(
      data => {
        this.paymentData = data;
        this.preSelectedPaymentOption = this.paymentData.payments.filter(option => option.default === 1);
        console.log('Preselected payment method: ', this.preSelectedPaymentOption.map(option => option));
      }, error => {
        console.log('Error', error);
      });
  }

3

Answers


  1. Your preSelectedPaymentOption might be undefined at the start so changing your condition to following should fix the issue

    *ngIf="!!preSelectedPaymentOption?.length && preSelectedPaymentOption[0].value === 3 && totalCartPrice > 380"
    
    Login or Signup to reply.
  2. The error could occur because of the Angular life cycle hooks.
    Do you get the Data before the Template is build?

    Here is the angular life cycle hook documentation:
    https://angular.io/guide/lifecycle-hooks

    Login or Signup to reply.
  3. The issue seems to be the fact that the data is being fetched over the network (using a webservice, I assume) and there is no guard for the duration when the view has loaded but the value has not yet been retrieved yet.

    Based on the answer by @jitender, you can check if preSelectedPaymentOption is not null before accessing it’s value.

    I would, however, recommend a cleaner full-RxJS approach as below:

    preSelectedPaymentOption$ = this.cartService.getPaymenyOptions()
      .pipe(
        take(1),
        tap((data) => {
          this.paymentData = data;
        }),
        map((data) => {
          return data.payments.filter((option => option.default === 1))
        }),
        tap((preSelectedPaymentOption) => {
          console.log('preselected payment method: ', preSelectedPaymentOption.map(option => option));
        }),
      );
    
    <ng-container *ngIf="(preSelectedPaymentOption | async) as preSelectedPaymentOption">
      <div *ngIf="preSelectedPaymentOption[0].value === 3 && totalCartPrice > 380" class="payment-warning">
        <ion-label>
          <h3>Atention!</h3>
          <p>Lorem ipsum dolor sit!!!.</p>
        </ion-label>
      </div>
    </ng-container>
    

    It is not clear from your code if you have any other use for preSelectedPaymentOption other than simply checking if preSelectedPaymentOption[0].value === 3.

    If you don’t need access to preSelectedPaymentOption for anything else except to check if the value === 3, then you can include that in the observable too:

    isPreSelectedPaymentOption$ = this.cartService.getPaymenyOptions()
      .pipe(
        take(1),
        tap((data) => {
          this.paymentData = data;
        }),
        map((data) => {
          const allOptionDefaultsToOne = data.payments.filter((option => option.default === 1));
          return (allOptionDefaultsToOne?.[0]?.value === 3);
        }),
      );
    
    <div *ngIf="(isPreSelectedPaymentOption$ | async) && totalCartPrice > 380" class="payment-warning">
      <ion-label>
        <h3>Atention!</h3>
        <p>Lorem ipsum dolor sit!!!.</p>
      </ion-label>
    </div>
    

    Note: I have not run this code, so it might contain errors. Please use your discretion.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search