Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mat-table angular 6 not showing any data despite having the dataSource

I want to show a list through Angular material design's data table mat-table. Here is my component:

import { LeaveapplicationService } from './../../services/leaveapplication.service';
import { leaveapplication } from './../../models/leaveapplication';
import { Component, OnInit, ViewChild, Input } from '@angular/core';
import { MatTableDataSource, MatPaginator, MatSort } from '@angular/material';
// import { DataSource } from '@angular/cdk/table';

@Component({
  selector: 'app-leaveapplication-list',
  templateUrl: './leaveapplication-list.component.html',
  styleUrls: ['./leaveapplication-list.component.scss']
})
export class LeaveapplicationListComponent implements OnInit {
  leaveApplications: leaveapplication[];
  displayedColumns: ['id', 'applicant', 'manager', 'leavetype', 'start', 'end', 'return', 'status'];
  dataSource: MatTableDataSource<leaveapplication>;

  constructor(private leaveApplicationService: LeaveapplicationService) { }

  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;

  ngOnInit() {
    this.leaveApplicationService.getLeaveApplications().subscribe(leaveapplications => {
      this.leaveApplications = leaveapplications;
      this.dataSource = new MatTableDataSource<leaveapplication>(this.leaveApplications);
      this.dataSource.paginator = this.paginator;
      this.dataSource.sort = this.sort;
      console.log(this.dataSource);
    });

  }

  applyFilter(filterValue: string) {
    filterValue = filterValue.trim(); // Remove whitespace
    filterValue = filterValue.toLowerCase(); // MatTableDataSource defaults to lowercase matches
    this.dataSource.filter = filterValue;
  }
}

The leaveapplication interface:

export interface leaveapplication {
  id: number; 
  applicant: string;
  manager: string;
  startdate: Date;
  enddate: Date;
  returndate: Date;
  leavetype: string; 
  status: string;
}

I am getting the dataSource properly in the console:

enter image description here

But the mat-table return empty cells:

enter image description here

Here is my template:

<mat-form-field>
  <input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
</mat-form-field>
<mat-table #table [dataSource]="dataSource" matSort class="mat-elevation-z8">
  <ng-container matColumnDef="id">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Form ID </th>
    <td mat-cell *matCellDef="let leaveapplication"> {{leaveapplication.id}} </td>
  </ng-container>
  <ng-container matColumnDef="applicant">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Applicant </th>
    <td mat-cell *matCellDef="let leaveapplication"> {{leaveapplication.applicant}} </td>
  </ng-container>

  <ng-container matColumnDef="manager">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Manager </th>
    <td mat-cell *matCellDef="let leaveapplication"> {{leaveapplication.manager}} </td>
  </ng-container>

  <ng-container matColumnDef="leavetype">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Leave Type </th>
    <td mat-cell *matCellDef="let leaveapplication"> {{leaveapplication.leaveType}} </td>
  </ng-container>
  <ng-container matColumnDef="start">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Start Date </th>
    <td mat-cell *matCellDef="let leaveapplication"> {{leaveapplication.startDate | date:'dd-MM-yyyy'}} </td>
  </ng-container>
  <ng-container matColumnDef="end">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> End Date </th>
    <td mat-cell *matCellDef="let leaveapplication"> {{leaveapplication.endDate | date:'dd-MM-yyyy'}} </td>
  </ng-container>
  <ng-container matColumnDef="return">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Return Date </th>
    <td mat-cell *matCellDef="let leaveapplication"> {{leaveapplication.returnDate | date:'dd-MM-yyyy'}} </td>
  </ng-container>
  <ng-container matColumnDef="status">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Status </th>
    <td mat-cell *matCellDef="let leaveapplication"> {{leaveapplication.status}} </td>
  </ng-container>
  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</mat-table>

<mat-paginator [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons></mat-paginator>

Why am I not getting the mat-table populated? Is it because of the asynchronous nature of the response?

like image 377
Efron A. Avatar asked Jun 04 '18 04:06

Efron A.


3 Answers

Hi i have a similar issue, where i can log the data of the DataSource but the Data Table, doesn't display the data.

I created an Array of Mock-Data in my service and passed this instead of the result i get from my database. With the Mock-Array it worked and i got data populated in my mat-table.

After i logged both, the result from the database and the Mock-Data, in the console i noticed that i get an object with an array inside from my database instead of just an array.

Browser console ->

MOCK-DATA: [ {...} ]

DATABASE: { [ {...} ] }

If you look closely you can see in your browser DOM, the data source is set to [Object object] and i think there is the problem, because the Mat-Table can't access the data.

I found a workaround, where i pass the array of the object instead of the object, which is a bit dirty, but does the job until i find the root of the issue.

Here is my service:

rfc.service.ts

@Injectable({
  providedIn: 'root'
})
export class RfcService {
  rfcsChanged = new Subject<Rfc[]>();
  private dbSubs: Subscription[] = [];

  <<MOCK-DATA>>

  constructor(private http: HttpClient) { }

  httpOptions = {
    headers: new HttpHeaders({
      'Content-Type': 'application/json'
    })
  };

  fetchRfcs() {...}

  cancelSubscriptions() {
    this.dbSubs.forEach(sub => sub.unsubscribe());
  }

After i changed my code from:

fetchRfcs() {
  this.dbSubs.push(
    this.http.get<Rfc[]>('http://localhost:3000/rfcs')
     .subscribe((rfcs: Rfc[]) => {
       // console.log(this.MOCK_RFCS);
       // console.log(rfcs);
       this.rfcsChanged.next(rfcs); 
     })
  );
}

to:

fetchRfcs() {
  this.dbSubs.push(
    this.http.get<Rfc[]>('http://localhost:3000/rfcs')
     .subscribe((rfcs: Rfc[]) => {
        // console.log(this.MOCK_RFCS);
        // console.log(rfcs.rfcs);
        this.rfcsChanged.next(rfcs.rfcs); 
     })
    );
}

it worked.

I don't know why my response array is wrapped in an object, but i recommend checking your service and how it receives the data. At the moment i try to find a way to map my response from the backend, so that it isn't wrapped inside an object.

How do you retrieve data in your service?

like image 51
Jan Tischhöfer Avatar answered Nov 20 '22 03:11

Jan Tischhöfer


You have a typo in your component.ts file: You do not assign the array of displayed columns to displayedColumns but instead only define your variable.

So, instead of

 displayedColumns: ['id', 'applicant', 'manager', 'leavetype', 'start', 'end', 'return', 'status'];

it should be

 displayedColumns: string[] = ['id', 'applicant', 'manager', 'leavetype', 'start', 'end', 'return', 'status'];
like image 42
XcodeJunkie Avatar answered Nov 20 '22 02:11

XcodeJunkie


In the ng-container of the above HTML code change as below.

From matColumnDef="start" to matColumnDef="startDate" From matColumnDef="end" to matColumnDef="endDate " From matColumnDef="return" to matColumnDef="returnDate"

The matColumnDef has to match exactly with the data column, otherwise data wont show up in the mat-table.

like image 2
Narender Gandi Avatar answered Nov 20 '22 03:11

Narender Gandi