Search code examples
angulardatatablesmartadmin

Angular2 - sa-datatable loads data only for the first time


The datagrid:

<sa-datatable [options]="{
                data: bundles,
                columns: [ {data: 'srNo'}, {data: 'name'}, { data: null, defaultContent: '<button class=\'btn btn-default\'>Details</button>' } ] }"
                paginationLength="true" tableClass="table table-striped table-bordered table-hover" width="100%">
    <thead>
        <tr>
            <th data-hide="phone">Sr. No.</th>
            <th data-class="expand"><i class="text-muted hidden-md hidden-sm hidden-xs"></i> Name</th>
            <th></th>
        </tr>
    </thead>
</sa-datatable>
<div> {{bundles.length }} </div>

The component:

Component({
    selector: 'tax-receipting-bundles',
    templateUrl: './tax-receipting-bundles.component.html',
    providers: [ TaxReceiptingBundleService ]
})

export class TaxReceiptingBundlesComponent implements OnInit  {
    bundles: TaxReceiptingBundle[];

    constructor(private service: TaxReceiptingBundleService) {
        this.bundles = [];
    }

    ngOnInit() {
        this.service.getBundles()
            .then(b=> {
                this.bundles = b; 
                console.log(this.bundles);
        });
}

The service:

@Injectable()
export class TaxReceiptingBundleService {
    getBundles() {
        return Promise.resolve(TAXRECEIPTINGBUNDLES);
  }
}

Mock Data

export const TAXRECEIPTINGBUNDLES: TaxReceiptingBundle[] = [
    {id: 1, srNo: 1, name: 'Bundles for February 2005'},
    {id: 2, srNo: 2, name: 'CDN Bundles'},
    .
    .
    {id: 12, srNo: 12, name: 'Bundles for April 2004'},
];

When I navigate to the component containing the datagrid, it shows the data correctly (12 records).

However, when I navigate away and come back to the same component, the grid is empty. However, the console.log in the ngOnInit() always logs all 12 records. But they're just now showing in the grid.

But the bundles.length prints 12 under the table -

enter image description here How can I fix this?


Solution

  • It seems the second time onwards, the datatable was getting rendered before getting the data for binding it with.

    I tried using setTimeOut, but it didn't work. What worked for me was using a resolver.

    I wrote an resolver service which returns a Promise of type TaxReceiptingBundle[] :

    @Injectable()
    export class TaxReceiptingBundlesResolver implements Resolve< TaxReceiptingBundle[]> {
        constructor(private cs: TaxReceiptingBundlesService, private router: Router) {}
    
        resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<TaxReceiptingBundle[]> {
    
            return this.cs.getBundles().then(c => {
                if (c) {
                    return c;
                } else { 
                    this.router.navigate(['/home']);
                    return null;
                }
            });
         }
     }
    

    Used the resolver in the path that required it:

    export const taxReceiptingRoutes: Routes = [
        {
            path: '',
            component: TaxReceiptingBundlesComponent,
            data: {
                pageTitle: 'Bundles Setup'
            },
            resolve: {
                bundles: TaxReceiptingBundlesResolver
            }
        }
    ]
    
    @NgModule({
        imports: [RouterModule.forChild(taxReceiptingRoutes)],
        exports: [RouterModule],
        providers: [TaxReceiptingBundlesResolver, TaxReceiptingBundlesService]
    })
    

    In the component, instead of getting data from the TaxReceiptingBundleService, I got it from the route object.

    constructor(private router: Router) { }
    
    ngOnInit() {
        this.route.data
            .subscribe((data: { bundles: TaxReceiptingBundle[] }) => {
                ..
        });
    }
    

    Now, the navigation waits for the list of TaxReceiptingBundles.