Search code examples
angulartypescriptangular6primengprimeng-turbotable

Object is an array when populating html table but not when iterating in typescript


I have a backend database that serves student records as JSON files. These objects are then populated in a PrimeNG table for display and selection.

student.component.html

<p-table class="table" [columns]="cols" [value]="searchResults">
    <ng-template pTemplate="header" let-columns>
        <tr>
            <th *ngFor="let col of columns">
                {{col.header}}
            </th>
       </tr>
    </ng-template>
    <ng-template pTemplate="body" let-rowData>
        <tr [pSelectableRow]="rowData" class="tr-click" (click)="getSelected(rowData)">
            <td *ngFor="let col of columns">
                {{rowData[col.field]}}
            </td>
        </tr>
    </ng-template>
</p-table>

However when I attempt to read or iterate through the student records in TypeScript, I get "TypeError: Cannot read property XXX of undefined".

student.component.ts

export class StudentComponent implements OnInit {

    searchResults: Student[];
    cols: any[];

    constructor(private router: Router, private studentService: StudentService, private http: HttpClient) {

    }

    ngOnInit(): void {
        this.studentService.getStudents().subscribe(data => {
            this.searchResults = data;
        });

        // table columns
        this.cols = [
            { field: 'studentId', header: 'Student ID'},
            { field: 'name', header: 'Name'},
            { field: 'dob', header: 'Date of Birth'},
            { field: 'status', header: 'Status'}
        ];

        // tested the object with these
        alert('1: ' + JSON.stringify(this.searchResults)); // undefined
        alert('2: ' + this.searchResults);                 // undefined
        alert('3: ' + this.searchResults.toString);        // undefined
    }

   // This is what I am trying to accomplish
   getSelected(selected: Student) {
       for (const result of this.searchResults) {
           if (selected.studentID === result.studentID) {
               // do some other stuff
       }
   }
}

So why is the PrimeNG table able to populate the table with the object, but I can't iterate over it in TypeScript? How do I get it to treat the object as an array?


Solution

  • apparently there is no columns declaration in your ts file

    <tr [pSelectableRow]="rowData" class="tr-click" (click)="getSelected(rowData)">
        <td *ngFor="let col of columns">
            {{car[col.field]}}
        </td>
    </tr>
    

    to

    <tr [pSelectableRow]="rowData" class="tr-click" (click)="getSelected(rowData)">
        <td *ngFor="let col of cols">
            {{car[col.field]}}
        </td>
    </tr>
    

    Edit: You are subscribing to an async method with subscribe, but you are trying to make assignments after subscription. because of this your function does not wait subscription to finish. The solution of your problem is :

    this.studentService.getStudents().subscribe(data => {
        this.searchResults = data;
    
         // table columns
        this.cols = [
          { field: 'studentId', header: 'Student ID'},
          { field: 'name', header: 'Name'},
          { field: 'dob', header: 'Date of Birth'},
          { field: 'status', header: 'Status'}
        ];
    
        // tested the object with these
        alert('1: ' + JSON.stringify(this.searchResults)); // undefined
        alert('2: ' + this.searchResults);                 // undefined
        alert('3: ' + this.searchResults.toString);        // undefined
    });