Data table is showing no data available in table using Angular

Viewed 30809

When I was trying to show data table in angular js. It shows no data available in table but there are 4 records in table. See screenshot below.

enter image description here

Here's what I did.

user.component.ts

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

import { UserModel }         from './user-model';
import { UserService }       from './user.service';
declare var $ :any;

@Component({
  selector: 'user-page',
  template: require('./user.component.html'),
  providers: [ UserService ]
})

export class UserComponent implements OnInit {

  data: any;
  errorMessage: string;

 constructor(private userService:UserService){ }

 ngOnInit() { 
  this.getUsers();
 }

 getUsers() {  
 this.userService.getUsers()
                 .subscribe(
                   users => {this.data = users; 
                              $(function(){
                               $("#user-table").DataTable();
                              });
                            },
                   error =>  this.errorMessage = <any>error);
  }
}

user.service.ts

import { Injectable }              from '@angular/core';
import { Http, Response }          from '@angular/http';
import { Headers, RequestOptions } from '@angular/http';

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';

import { UserModel } from './user-model';

@Injectable()
export class UserService {
      private usersUrl = 'http://localhost/larang/public/api/users';  
constructor (private http: Http) {}

getUsers(): Observable<UserModel[]> { 
 return this.http.get(this.usersUrl)
                .map(this.extractData)
                .catch(this.handleError);
}


private extractData(res: Response) { 
  let body = res.json();

  return body.data || { };
}

private handleError (error: Response | any) { console.log(error);

 let errMsg: string;
 if (error instanceof Response) {
  const body = error.json() || '';
  const err = body.error || JSON.stringify(body);
  errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
 } else {
   errMsg = error.message ? error.message : error.toString();
 }
console.error(errMsg);
return Observable.throw(errMsg);
 }
}

user.component.html

<table id="user-table" class="table table-bordered table-hover">
 <thead>
      <tr>
        <th>Name</th>
        <th>Email</th>
        <th>Added On</th>
      </tr>
 </thead>
 <tbody>
       <tr *ngFor="let item of data">
         <td>{{item.name}}</td>
         <td>{{item.email}}</td>
         <td>{{item.added}}</td>
       </tr>
 </tbody>
</table>

this.data looks like this

[
 {"name":"John Doe","email":"john.doe@gmail.com","added":"2017-04-26"},
 {"name":"Ramkishan","email":"Ramkishan@gmail.com","added":"2017-04-26"},
 {"name":"Jason Bourne","email":"jason@gmail.com","added":"2017-04-26"},
 {"name":"RK","email":"ramkishan.suthar@ranosys.com","added":"2017-04-26"}
]

What I am doing wrong please help. It will be very helpful for newbies in Angular JS like me.

8 Answers

So in my case DataTables are getting activated before I got the response from the server. I just added *ngIf for my table and it worked for me. Like below.

<table *ngIf="dataService.users" datatable="ng" [dtOptions]="dtOptions">

Using a Timeout function is a bad practice. As you are using angular, the best way to solve this is by using change detection.

First create this instance by adding it in the constructor like this,

... constructor(private chRef: ChangeDetectorRef) { } ... in the component where you want to use datatables.

Now use the detectChanges function so that angular waits till something is changed(in your case, till the table is generated properly)

ngOnInit() { 
  ... 
   this.chRef.detectChanges();
   const table: any = $('table');
   this.dataTable = table.DataTable(); 
  ...
 }

So that one line this.chRef.detectChanges() really fixes the issue.

  1. add this code on the constructor:

    private changeDetectorRef: ChangeDetectorRef
    
  2. On theuser.component.ts -> getUsers(), you can add a complete function:

    this.userService.getUsers().subscribe(users => {
        this.data = users;
    },
    error => { this.errorMessage = <any>error },
    () => {
        //Complete
        this.changeDetectorRef.detectChanges();
        const table: any = $("#user-table").DataTable();
        this.dataTable = table.DataTable();
    });
    

The problem happens because the table gets rendered before you get your data.

Although it is not a proper solution but adding a timeout solves this.

To your datatable add this *ngIf="showContent":

  <table datatable="ng" *ngIf="showContent" [dtOptions]="dtOptions" class="row-border hover table-bordered">

and then in your component .ts file add this to ngOnInit()

setTimeout(()=>this.showContent=true, 250);

also declare the dummy variable showContent.

Hope it helped.

I just experienced similar and this is how I solved mine. Am putting it out here so that in case I forget in the future, I can find it and probably help others who stumble upon this.

<table *ngIf="userList.length" datatable class="table table-hover table-striped table-bordered mb-5">

I didnt like the other solutions because I was using similar in my older projects and sometimes it disturbs the user experience when recreating the table on data refresh and stuffs like that but this solved it and working fine. The issue I believe was a time lapse between the initialization and when the server return data to the datatable.

According to the documentation here, add the following css to your styles.css

/*
server-side-angular-way.component.css
 */
.no-data-available {
  text-align: center;
}

/*
   src/styles.css (i.e. your global style)
*/
.dataTables_empty {
  display: none;
}

This will not show 'No Data' when you have data.

Related