Ramkishan Suthar
Ramkishan Suthar

Reputation: 403

Data table is showing no data available in table using Angular

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":"[email protected]","added":"2017-04-26"},
 {"name":"Ramkishan","email":"[email protected]","added":"2017-04-26"},
 {"name":"Jason Bourne","email":"[email protected]","added":"2017-04-26"},
 {"name":"RK","email":"[email protected]","added":"2017-04-26"}
]

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

Upvotes: 12

Views: 37435

Answers (9)

Mohit Baman
Mohit Baman

Reputation: 1

I can understand your issue you have to add a length check condition this will solve your problem.👍👍👍👍 use this in your tbody

 <tbody  *ngIf="mainData.length">
         <tr *ngFor="let group of mainData; let i = index">
                <td>{{i+1}}</td>
                <td><img class="img-thumbnail " style="width: 100px;" src="{{imgUrl}}{{group.cat_image}}"/></td>
                <td>{{group.cat_name}}</td>
               <td>{{group.cat_slug}}</td>
               <td>   <ul *ngFor="let item of mainData"><li  *ngIf="group.cat_id==item.parent && item.cat_id != group.cat_id" class="d-block"><i class="bi bi-caret-right-fill"></i> {{item.cat_name}}</li></ul></td>
               <td>{{group.created_on}}</td>
               <td>{{group.updated_on}}</td>
               <td>
            

                <a href="javascript:;" class="btn btn-sm btn-primary mr-2" style="margin-right: 10px;"><i class="bi bi-pencil-square"></i></a>
                <a href="javascript:;" class="btn btn-sm btn-danger ml-2"><i class="bi bi-trash3"></i></a>
            </td>
           </tr>
        </tbody>

Upvotes: 0

OneGhana
OneGhana

Reputation: 117

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.

Upvotes: 1

jayesh wasnik
jayesh wasnik

Reputation: 1

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.

Upvotes: 0

Kihats
Kihats

Reputation: 3520

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.

Upvotes: -2

Nikhil Bhandarkar
Nikhil Bhandarkar

Reputation: 709

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">

Upvotes: 20

Thomas Gicquel
Thomas Gicquel

Reputation: 71

  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();
    });
    

Upvotes: 0

Akshay L Kalkur
Akshay L Kalkur

Reputation: 548

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.

Upvotes: 1

hasitha lakthilina
hasitha lakthilina

Reputation: 91

Added Time out for solve your problem.

 setTimeout(function () {
  $(function () {
    $('#user-table').DataTable();
  });
}, 3000);

refer this video link I found on youtube https://www.youtube.com/watch?v=78X8ZRU9Hy8

Upvotes: 7

stephane
stephane

Reputation: 292

In your user.component.ts, declare your data var empty to initialize it. I don't know why but I had the same problem when I refresh the page. I think the data is lost so you need to initialize it. Maybe datatable needs to know there is an Array and after you fill it it's working.

    ngOnInit(){
        this.data = [];
        this.getUsers();
    }

I WAS WRONG

You have to rerender the datatable because if you rerender the initialisation throw an error, that's why you have the message saying "no data available" despite you have in the table.

UPDATE

In your component, declare this variable:

  @ViewChild(DataTableDirective)
  dtElement: DataTableDirective;
  dtOptions: DataTables.Settings = {};
  dtTrigger: Subject<any> = new Subject();

after you pull your data from whatever service you have:

this.officeSrv.getAll().subscribe((data) => {
  console.log('----> office service : get all data', data);
  this.offices = data.offices;

  // ADD THIS
  this.dtTrigger.next();

}, (err) => {
  console.log('-----> err', err);
})

If you have modification to make modification directly in the same datatable without changing the page create and call this function

rerender(): void {
 this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
   // Destroy the table first
   dtInstance.destroy();
   // Call the dtTrigger to rerender again
   this.dtTrigger.next();
 });
}

Use this library in your component:

    import { DataTableDirective } from 'angular-datatables';

In your app module:

    import { DataTablesModule } from 'angular-datatables';

And declare this :

    imports: [
           ...,
           DataTablesModule

And finally for your templating (HTML):

   <table datatable [dtOptions]="dtOptions" [dtTrigger]="dtTrigger" class="table table-hover table-striped table-bordered" cellspacing="0"
      width="100%">
      <thead>
        <tr>
          <th>Nom</th>
          <th>Adresse</th>
          <th>Actions</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let office of offices">
          <td>{{office.name}}</td>
          <td>{{office.adress}}</td>
          <td>
            <div class="btn-group">
              <button type="button" class="btn btn-block btn-info">Action</button>
              <button type="button" class="btn btn-primary btn-outline-info dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"
                aria-haspopup="true" aria-expanded="false">
              <span class="sr-only">Toggle Dropdown</span>
            </button>
              <div class="dropdown-menu">
                <a class="dropdown-item" (click)="update(office._id)">Mettre à jour</a>
                <a class="dropdown-item" (click)="delete(office._id)">Supprimer</a>
              </div>
            </div>
          </td>
        </tr>
      </tbody>
    </table>

Hope that's help

src : https://l-lin.github.io/angular-datatables/#/advanced/rerender

Upvotes: 17

Related Questions