2

I'm using Angular Datatables, in angular 6. My code works, I see the table I can render it. I can't search I can't control how many items get displayed, the footer says "Showing 0 to 0 of 0 entries" and "no data available in the table"

users.ts

  ngOnInit() {
    this.dtOptions = {
      pagingType: 'full_numbers',
      pageLength: 7,
      deferRender: true,
      retrieve: true
    };
    if (localStorage.getItem('data') !== null) {
      const data = JSON.parse(localStorage.getItem('data'));
      this.item = data.body.response;
      if (Array.isArray(this.item.domains) || this.item.domains.length) {
        for (let i = 0; i < this.item.domains.length; i++) {
          this.users.getUsers(this.item.domains[i].id).subscribe((res: any) => {
            this.domain_users = res.response.items;
            // the api returns arrays and so I had to iterate over them, and not all of them
            // the first array is empty
            for (let j = 0; j < this.domain_users.length; j++) {
              if (this.domain_users[j].user !== undefined) {
                this.user.push(this.domain_users[j].user);

              }
            }
          }, error => {
            console.log('getUsers error, probably session expired on the server ' + error);
          });
        }
      }
    }
  }
  ngAfterViewInit(): void {
    this.dtTrigger.next();
  }
  ngOnDestroy(): void {
    // Do not forget to unsubscribe the event
    this.dtTrigger.unsubscribe();
  }
  rerender(): void {
    this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
      // Destroy the table first
      dtInstance.destroy();
      // Call the dtTrigger to rerender again
      this.dtTrigger.next();
    });
  }

html

<table id="detailed-resource-optria" datatable [dtOptions]="dtOptions" [dtTrigger]="dtTrigger" class="compact row-border hover cell-border"
    data-page-length='10'>
    <thead>
        <tr>
            <th>First Name</th>
            <th>Last Name</th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor="let item of user">
            <td>{{item.profile?.fname}}</td>
            <td>{{item.profile?.lname}}</td>

        </tr>
    </tbody>
</table>

I pretty much sure the problem is because I'm populating the table directly from this.user without going through dtOptions, I don't know how to fix it though, I tried supplying data from the array, as the source, that won't work.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Lynob
  • 5,059
  • 15
  • 64
  • 114
  • Why do you create `this.dtOptions` multiple times? – Frank Modica Aug 20 '18 at 19:20
  • You do `this.dtOptions = { ... }` inside of a loop, so you create that object potentially multiple times. I don't know if it's related to your problem, but it seemed odd. – Frank Modica Aug 20 '18 at 19:26
  • @FrankModica Nice catch! I fixed it thank you, but it's unrelated to my question, the problem is there still – Lynob Aug 20 '18 at 19:29
  • did you try running `this.dtTrigger.next();` manually after pushing all the data into `this.user`? as suggested here: https://l-lin.github.io/angular-datatables/#/basic/angular-way – derelict Aug 20 '18 at 19:52
  • @derelict I tried it earlier didn't work, I tried it now, it worked, I just removed all existing `this.dtTrigger.next();` and then I did exactly as you said, it worked. Please post an answer so I can accept it – Lynob Aug 20 '18 at 19:57
  • try this link [Datatables Plugin with Angular 6](https://stackoverflow.com/questions/51363693/using-full-featured-datatables-plugin-with-angular-6/52243687#52243687) – Sanjay kumar Sep 09 '18 at 10:54
  • @Sanjaykumar would it make any difference over the existing answer? coz the current accepted answer is working – Lynob Sep 09 '18 at 13:26

2 Answers2

2

If you need use a large amount of Observable, use forkJoin

//define an array of observables
let request:Observable[]=[]
if (Array.isArray(this.item.domains) || this.item.domains.length) {
    for (let i = 0; i < this.item.domains.length; i++){
         //just fill the array of observables
         request.push(this.users.getUsers(this.item.domains[i].id))      
    }
    forkJoin(request).subscribe((response:any[])=>{
         //in response[0], we have the response of getUsers(this.item.domain[0].id)
         //in response[1], we have the response of getUsers(this.item.domain[1].id)
         ....
         for (let res in response)
         { 
             //You can use concat and filter
             let users=Res.response.items
                 .filter(us=>us.user!=undefined)
                 .map(us=>us.user);
             this.user.concat(users);
         }
    })
}
Eliseo
  • 50,109
  • 4
  • 29
  • 67
  • interesting, I had to accept his answer though since his answer solve the problem i asked. But I think your answer is more important to me,personally, regardless of the datatables, it's an improvement of the most vital piece of code in the app. Since most data are processed in the same way – Lynob Aug 20 '18 at 20:31
2

did you try running this.dtTrigger.next(); manually after pushing all the data into this.user? as suggested here: l-lin.github.io/angular-datatables/#/basic/angular-way

(comment promoted to answer at op's request)

i'm guessing it's just a timing thing -- since your async queries weren't returning until after the ngAfterViewInit method had run, it needed an extra trigger after all data had been loaded. glad it worked :)

derelict
  • 2,044
  • 10
  • 15