问题
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