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:
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}] = [];
Wrap the whole table html into ng-container:
<ng-container *ngIf="reportElements"> <table></table> </ng-container>
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.