Angular - NGXS problem with loading data before view

2k Views Asked by At

Have you encountered a problem when you route to component and loading a table. But table is empty without data.

I mean the component / table is displayed. Data as i can see are in state(seassion storage] and loaded. I am able to display them if i refresh the page.

By the way i could dispatch state before this component and my problem could be solved or use simple service with call on api. But this is not solution for me.

So my problem is = how could i display / load data before view?

My assets.state.ts

    @Action(SetDevice)
  async setDevice({ patchState, dispatch }: StateContext<DeviceDataModel>) {
    return await this.deviceListService.getData().subscribe((response: DeviceDataModel) => {
      console.log(response);
      patchState({
        data: response.data,
        dataSet: response.dataSet,
        offset: response.offset,
        size: response.size,
      });
      dispatch(new SetDeviceSuccess());
    });
  }

Component - set data into state and load them into table some.component.ts

ngOnInit(): void {
    this.store.dispatch(new SetDevice());
    this.getTableData();
  }

getTableData() {
    this.tableData = this.store.selectSnapshot(DeviceState.getDataDevice);
  }

some.component.html

 <dynamic-table
        style="width: 85%;"
        *ngIf="tableData"
        [tableData]="tableData.data"
        [tableColumns]="tableCols"
        [url]="'devicelist'"
      ></dynamic-table>

Thank you in advance for any help or idea.

3

There are 3 best solutions below

0
On BEST ANSWER

I resolve this issue with toPromise() and then(). I know its not a best aproceh. But now its working.

So I simply replace this code with code below.

   ngOnInit(): void {
    this.store.dispatch(new SetDevice());
    this.getTableData();
  }

getTableData() {
    this.tableData = this.store.selectSnapshot(DeviceState.getDataDevice);

  }

First of all I display spinner and after receiving data I just hide spinner and display table thanks to .then()

 ngOnInit(): void {
     this.store
      .dispatch(new SetAccount())
      .toPromise()
      .then((result) => {
       console.log(res);
       this.getTableData();
      });
}
2
On

Most likely your data is not loaded yet when you call selectSnapshot. You are way better of using a @Select statement:

@Select(DeviceState.getDataDevice)
readonly tableData$!: Observable<any>;

ngOnInit(): void {
  this.store.dispatch(new SetDevice());
}

and have your template use the async pipe:

<dynamic-table *ngIf="tableData$ | async as tableData"
   [tableData]="tableData.data"
   [tableColumns]="tableCols"
   [url]="'devicelist'">
</dynamic-table>

Besides that, your @Action handler is wrong as well, that's not how you use async/await and an Observable. You need to return the Observable from the action handler, to make sure that when the action completes, and you subscribe to the dispatch, it will be done by then:

@Action(SetAssets)
setWorkflows({ patchState, dispatch }: StateContext<AssetDataModel>) {
  return this.assetListService.getData().pipe(
    switchMap((response: AssetDataModel) => {
      patchState({
        data: response.data,
        dataSet: response.dataSet,
        offset: response.offset,
        size: response.size,
      });

      return dispatch(new SetDeviceSuccess());
    })
  )
}
5
On

The problem is that you are calling this.getTableData(); function before the data is loaded.

some.component.ts

    @Select(state => state.youdata) yourdata$: Observable<any>;

    ngOnInit(): void {
        this.store.dispatch(new SetDevice()); 
     }

some.component.html

 <dynamic-table
            style="width: 85%;"
            *ngIf="tableData"
            [tableData]="tableData.data | async"
            [tableColumns]="tableCols"
            [url]="'devicelist'"
          ></dynamic-table>