简体   繁体   中英

Angular *ngFor Data Matching

I need help to find the correct way to display my JSON data in Angular 7 template. As you can see in my JSON sample below, I have a person object with multiple identification numbers, I'm using *ngFor to display them in the template, and uses *ngIf to match the type and display the number. However, this method will only show fields where data is available, if the student ID is not returned from the JSON object, the whole field including the label will not be displayed.

My first is, am I doing the right thing by using *ngIf to match the id type inside the ngFor?

Secondly, is there another way to represent the identification data where if id type is not available, for example the studentID type is not returned , I can use the template to display N/A?

*UPDATED the duplicated passport mistake

JSON Data Sample

person = {
  name: { firstname: "John ", lastname: "Smith" },
  identification: [
  { type: "ID", number: "CSG112345", },
  { type: "PASSPORT", number: "AB4455566" }   
  ]}

Template

<ng-container *ngFor="let id of person.identification">
  <p *ngIf="id.type==='ID'">
    <label>ID:</label>
    <b>{{id.number}}</b>
  </p>
  <p *ngIf="id.type==='PASSPORT'"  >
    <label>Passport Number :</label>
    <b>{{id.number}}</b>
  </p>
  <p *ngIf="id.type==='STUDENTID'">
    <label>Student Number :</label>
    <b>{{id.number}}</b>
  </p>
</ng-container>

The *ngIfs arent wrong. Just the ngSwitch is much cleaner. You can use ternary operator in template to set a default value.

   <ng-container *ngFor="let id of person.identification">
    <ng-container [ngSwitch]="id.type">
      <p *ngSwitchCase="'PASSPORT'">
        <label>Passport :</label>
        <b>{{id.number ? id.number : 'N/A'}}</b>
      </p>
      <p *ngSwitchCase="'PASSPORT'">
        <label>Passport Number :</label>
        <b>{{id.number ? id.number : 'N/A'}}</b>
      </p>
      <p *ngSwitchCase="'STUDENTID'">
        <label>Student Number :</label>
        <b>{{id.number ? id.number : 'N/A'}}</b>
      </p>
    </ng-container>
   </ng-container>

Also you have duplication of PASSPORT. Don't know if that is intended. Since we are iterating an array to the template, you should provide a default value for none existing members before you display it. That would be my aproach. Otherwise you would need to make a fn like

checkForType(type:string):boolean{
 return person.identification.map(e => e.type).includes(type)
};

And check for it in the template. Something like

<ng-container *ngIf="checkForType(id.type)">
.....
</ng-container>
<ng-container *ngIf="!checkForType(id.type)">
.....
</ng-container>

But this will create a lot of bloating of the html file. I would suggest you give it a default value before rendering it to the html.

<b>{{id.number ? id.number : 'N/A'}}</b>

只需使用此行代替<b>{{id.number}}</b>您将获得预期的输出。

If you want to show each template element, just add condition in <b> itself. see updated stackblitz. https://stackblitz.com/edit/angular-tqixcb

<p>
   <label>Name :</label>
   <b>{{person.name.firstname}}</b>
</p>
<p>
   <label>ID :</label>
   <b>{{getNumber("ID")}}</b>
</p>
<p>
   <label>Passport Number :</label>
   <b>{{getNumber("PASSPORT")}}</b>
</p>

ts method:

  getNumber(type): String {
    const numberValue = this.person.identification.find(x => x.type === type);
    if(!numberValue) {
      return "N/A"
    }
    return numberValue.number;
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM