0

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.

Daniel Vágner
  • 538
  • 3
  • 19
  • Hello, this is not an answer. But in order to answer you, I want you to try it. Can you replace `this.getTableData();` with `setTimeout(() => { this.getTableData();}, 2000);` – M Fuat Aug 04 '20 at 06:41
  • @MFuatNUROĞLU yes this is working. Finally after timeout the data are displayed. But is there a better approach ? – Daniel Vágner Aug 04 '20 at 06:52
  • `this.store.dispatch(new SetDevice()).subscribe(()=> {this.getTableData();})` Can you tell me if this works for you to write it as answer? – M Fuat Aug 04 '20 at 07:13
  • The answer from @Poul Kruijt is correct for how you'd want to structure your state with Observables. What's not clear to me is that you are calling dispatch on `SetDevice` but not waiting for it to complete before loading table data - but the state code is referring to `SetAssets` ( a different action) so I don't see how devices and assets link together – Garth Mason Aug 04 '20 at 07:32
  • I post different state, my mistake. But both are the same. There is only different name and Interface. And no, this answer not working for me.... the table is empty until i refresh page. So far, the only solution has been setTimeout, and that doesn't seem like the best approach. – Daniel Vágner Aug 04 '20 at 07:40
  • Refresh the page? That would reset the state again back to default (unless you are using the state storage plugin). I can't see how `setTimeout` would be required though so something else is missing. If you can reproduce it in a stackblitz might be able to find the problem. – Garth Mason Aug 04 '20 at 07:49
  • Yes i am using a storage plugin. I will provide stackblitz and post it. But first i neeed to finish my work. So it means with refresh / reoad page. Data are displayed and state is not reset to default. If i close the page, browser - after that state is reseted. Its work fine. Only problem is with loading data and i don't get it too with that setTimeout. But its working... – Daniel Vágner Aug 04 '20 at 07:53
  • No worries mate, good luck! – Garth Mason Aug 04 '20 at 07:59

3 Answers3

2

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());
    })
  )
}
Poul Kruijt
  • 69,713
  • 12
  • 145
  • 149
0

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>
M Fuat
  • 1,330
  • 3
  • 12
  • 24
0

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();
      });
}
Daniel Vágner
  • 538
  • 3
  • 19