Search code examples
angulartypescriptrxjsangularfire2ngx-datatable

ngx-datatable Can't reassign the row model in case of [rows]="rows | async"


I'm using Angular 2 (4.1.0), angularfire2 and ngx-datatable.

I have component with a datatable that is rendering an Observable. The Observable is based on Angularfire2. The user can filter on the name column, implemented like in the ngx-datatable filter demo. I'm querying firebase for a new result set and try to assign the new Observable to the row model of the datatable, but this does not work:

ERROR TypeError: Cannot read property '0' of null
    at DataTableBodyComponent../src/components/body/body.component.ts.DataTableBodyComponent.updateRows (index.js:4384)
    at DataTableBodyComponent../src/components/body/body.component.ts.DataTableBodyComponent.recalcLayout (index.js:4599)
    at DataTableBodyComponent.set [as rows] (index.js:4185)
    at updateProp (core.es5.js:10966)
    at checkAndUpdateDirectiveDynamic (core.es5.js:10726)
    at checkAndUpdateNodeDynamic (core.es5.js:12111)
    at checkAndUpdateNode (core.es5.js:12055)
    at debugCheckAndUpdateNode (core.es5.js:12681)
    at debugCheckDirectivesFn (core.es5.js:12622)
    at Object.eval [as updateDirectives] (DatatableComponent.html:24)
    at Object.debugUpdateDirectives [as updateDirectives] (core.es5.js:12607)
    at checkAndUpdateView (core.es5.js:12019)
    at callViewAction (core.es5.js:12334)
    at execComponentViewsAction (core.es5.js:12280)
    at checkAndUpdateView (core.es5.js:12025)

Expected behavior:

After filtering and getting the new Observable I want the datatable to render the new Observable.

Here are the most important code snippets:

HTML, Datatable (I'm using [rows]="rows | async" !) :

...
<ngx-datatable #table [rows]="rows | async" 
 [columnMode]="'flex'" [headerHeight]="50" [footerHeight]="50" [rowHeight]="'auto'"
 [limit]="10" class="material striped" [selected]="selected" [selectionType]="'single'"
 (select)='onSelect($event)'>
...

The component:

@Input()
  set onFilteringList (filter: string) {
    this._onFilteringList = filter;
    // assignment after the table has been rendered throws error!
    this.rows = this.workItemSrv.getFilteredByUserWorkItemList(this.onFilteringList);
  }
ngOnInit() { // OK, everything worked fine here 
    if (this.onFilteringList) {
      this.rows = this.workItemSrv.getFilteredByUserWorkItemList(this.onFilteringList);
    } else {
      this.rows = this.workItemSrv.getWorkItemList();
    }
  }

I have tried three different way to display a filtered result set:

  1. Routing: using route parameters (as filter params) looks promising, but the component is not reinitialized with every navigation. After initial routing, init of the component, and rendering the table I get an error like I have described above (please, see the code snippets).

  2. using firebase query methods, but there is no way to define a query with a parameter so that either all items are retrieved or a filtered subset of all items. Using an Observable with a filter applied and a second Observable with no filter might be a solution, but I need to swap the row model on the datatable. And this results in an error as stated above.

  3. using rxjs filter method, but i did not found a solution to successfully apply a filter on the Observable

None of these gives me a solution. :-(

How can I either change the row model of the data table or do a filtering on the Observable?

Thanks, Markus


Solution

  • You can try to avoid using async data model:

    ...
    <ngx-datatable #table [rows]="rows" 
    ...
    

    And component changes:

    @Input()
    set onFilteringList (filter: string) {
      this._onFilteringList = filter;
      this.workItemSrv.getFilteredByUserWorkItemList(this.onFilteringList)
        .subscribe(rows => this.rows = rows);
    }
    
    ngOnInit() { 
      if (this.onFilteringList) {
        this.rows = 
        this.workItemSrv.getFilteredByUserWorkItemList(this.onFilteringList)
           .subscribe(rows => this.rows = rows);
      } else {
        this.rows = this.workItemSrv.getWorkItemList()
          .subscribe(rows => this.rows = rows);
      }
    }