angularangular-materialangular-akita

Angular material datatable paginator returns undefined when using Akita Entity Store plugin


I have been stuck with this for two days and I hope someone can point me to a solution. I have an Angular application using Akita for state management and one of the components is tasked with loading a list of customers. I have placed the important bits of my code below.

// customers.component.ts
export class IndexComponent implements OnInit, AfterViewInit, OnDestroy {
    
    // Constructor and other definitions are here

    customers$: Observable<Customer[]>;
    @ViewChild(MatPaginator) private _paginator: MatPaginator;
    @ViewChild(MatSort) private _sort: MatSort;

    ngOnInit(): void {
        this.customerService.get().subscribe();

        this.customers$ = this._customersQuery.customers$;
    }

    ngAfterViewInit(): void {
        if (this._sort && this._paginator) {
            // Code here is never executed
        }
    }
}

// customer.service.ts
export class CustomerService extends NgEntityService<CustomerState> {
    
    // Constructor is here
    
    get() {
        return this.http.get<Customer[]>('/api/customers').pipe(
            tap(entities => {
                this.CustomerStore.set(entities);
            })
        );
    }
}

// customer.query.ts
export class CustomerQuery extends QueryEntity<CustomerState> {

    public customers$: Observable<Customer[]> = this.selectAll();

    constructor(protected store: CustomerStore) {
        super(store);
    }

}

// customer.component.html
<ng-container *ngIf="(customers$ | async) as customers">
    <ng-container *ngIf="customers.length > 0; else noCustomers">
        // The table goes here
        <mat-paginator>
            // Paginator options go here
        </mat-paginator>
    </ng-container>
</ng-container>

<ng-template #noCustomers><p>No Customers</p></ng-template>

No matter what I do, I always get an undefined Paginator instance. I am not sure what I am doing wrong. I would appreciate any assistance. Thank you.


Solution

  • The problem is that the element that you are using ViewChild on is in an ngIf:

          @ViewChild(MatPaginator) private _paginator: MatPaginator;
    

    The paginator you are trying to bind to isn't in the DOM when the component is initialized, because it's hidden by the ngIf, therefore the binding doesn't occur.

    This is a long discussion on how to get around this issue. The TLDR solution is to use bind to the native HTML hidden property and flip your ngIf logic. That's not so simple with your code because of the nesting of ngIfs and using ng-containers, not divs.