Skip to content
Advertisement

Error in *ngIf on one element not letting *ngFor to work properly on another

Initialization of variable in one element and error in console that I had been ignoring all along, created a problem elsewhere in another element. Why does angular behave this way?

When I do not initialize another variable, which I am using with *ngIf, javascript throws up “undefined” while testing its length (expected). But this also causes *ngFor to not work properly for the dropdown (no data gets loaded – unexpected). Btw I realized, this is not just happening with datalist; *ngFor fails on any component if *ngIf has error in this code.

So, why does *ngFor fail for dropdown (first element) when *ngIf condition can’t be validated on table (another element)? Should I think about this in a different way that Angular is a framework and may behave erratically if I don’t do a good job in managing errors on its constructs?

Below is the code to reproduce error. Uncomment the suggested line and error will go away…

HTML

<div class="row">
    <div class="col">
        <input
          type="text" class="form-control" list="tktnum"
          placeholder="Ticket Number..." [(ngModel)]="tktNum"
        >
        <datalist id="tktnum">
            <option *ngFor="let a of tktVals">{{a.TicketNo}}</option>
        </datalist>
    </div>
</div>
<br><br>

<div class="row">
    <div class="col">
        <table class="table table-hover table-striped table-dark table-bordered"
            *ngIf="reportElements.length > 0">
            <thead>
                <tr>
                    <th scope="col">Ticket Number</th>
                </tr>
            </thead>
            <tbody>
                <tr *ngFor="let _ of reportElements">
                    <td>{{ _.F1 }}</td>
                </tr>
            </tbody>
        </table>
    </div>
</div>

Typescript

import { Component, OnInit, VERSION } from "@angular/core";

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit {
  reportElements: [{F1: 3}];

  tktVals: Array<{ TicketNo: string }> = [{ TicketNo: "1" }, { TicketNo: "2" }];
  tktNum: any;

  constructor() {}

  ngOnInit(): void {
    this.tktVals = [{ TicketNo: "1" }, { TicketNo: "2" }];
    
    //Uncomment the following line of code and it will start working as expected.
    //this.reportElements = [{F1: 3}];

    console.log(this.reportElements.length);
  }
}

Advertisement

Answer

The problem is that reportElements is undefined initially. You cannot actually use the length of “undefined because it doesn’t have a property of length, and you cannot also iterrate on it because undefined is not iterrable. There’re multiple ways to solve it:

  1. Give an initial value of an empty array to reportElements. But in this case you need to care about removing/changing its type notation:

     reportElements: [{F1: 3}] = [];
    
  2. Wrap the whole table html into ng-container:

     <ng-container *ngIf="reportElements">
         <table></table>
     </ng-container>
    
  3. Change the existing *ngIf of the table to the following one:

     *ngIf="reportElements && reportElements?.length > 0"
    

When an error in template expression happens, it makes all other expressions in the same template to fail. That’s why both your table and select are broken.

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement