Opening modal using NGX and state management

陌路散爱 提交于 2020-02-21 06:32:52

问题


I'd like to use NGXS to open modal which will set column visibility for datatable.

Here is my code:

state.ts file:

@Action(OpenColumnModal)
openColumnModal(ctx: StateContext<FeedStateModel>) {
    const state = ctx.getState();
    const allCols = state.allColumns;
    return this.modalService.openColumnVisibilityModal(allCols).pipe(tap((result) => {
        ctx.setState({
            ...state,
            allColumns: result,
            userColumns: result.filter(col => col.visible)
        });
    })
}

modal.service.ts:

openColumnVisibilityModal(columns): Observable<any> {
    const dialogRef = this.dialog.open(ColumnVisibilityModal, {
        data: columns,
        autoFocus: false,
        hasBackdrop: true,
        disableClose: true
    });

    return dialogRef.afterClosed();
}

When I'm using modal opened by NGXS, after closing the state event isn't emitted. After that, I need to click somewhere to call the callback function inside openColumnModal function.

I'm using Angular Material dialog.

Does anyone know how to call callback function automatically after closing modal?

Thanks in advance:)


回答1:


P.S. - other answers that advise to subscribe inside the action handler are not correct, as NGXS doesn't work like that!

Your current approach is correct, the problem is that action handlers are run outside Angular's zone. Just inject the NgZone class into your state and execute the code within Angular's zone:

constructor(private modalService: ModalService, private zone: NgZone) {}

@Action(OpenColumnModal)
openColumnModal(ctx: StateContext<FeedStateModel>) {
  const state = ctx.getState();
  const allCols = state.allColumns;
  return this.zone.run(() =>
    this.modalService.openColumnVisibilityModal(allCols).pipe(
      tap(result => {
        ctx.setState({
          ...state,
          allColumns: result,
          userColumns: result.filter(col => col.visible)
        });
      })
    )
  );
}

When you dispatch any action - NGXS invokes the appropriate handlers for this action within the parent zone using runOutsideAngular, this is by design.

You can also look at the executionStrategy option that allows to provide own class or use existing NoopNgxsExecutionStrategy, that doesn't use NgZone class at all.




回答2:


To add to Armen's anser: Pipe is used to chain different functions and returns an Observable. Tap is used within pipe to run a side effect (like logging values in between pipes to debug, etc).

Check out this RxJS docs page and you can read:

Note: this is different to a subscribe on the Observable. If 
the Observable returned by tap is not subscribed, the side 
effects specified by the Observer will never happen. tap 
therefore simply spies on existing execution, it does not 
trigger an execution to happen like subscribe does.

In other words: if you don't subscribe to the Observable returned by your pipe, the pipe won't run at all. Your fix:

return this.modalService.openColumnVisibilityModal(allCols).subscribe((result) => {
    ctx.setState({
        ...state,
        allColumns: result,
        userColumns: result.filter(col => col.visible)
    });
});



回答3:


Try to use subscribe instead of pipe:

@Action(OpenColumnModal)
openColumnModal(ctx: StateContext<FeedStateModel>) {
    const state = ctx.getState();
    const allCols = state.allColumns;
    return this.modalService.openColumnVisibilityModal(allCols).subscribe(result => {
        ctx.setState({
            ...state,
            allColumns: result,
            userColumns: result.filter(col => col.visible)
        });
    })
}


来源:https://stackoverflow.com/questions/56831420/opening-modal-using-ngx-and-state-management

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!