7
votes

Is there any good solution when working with modals in a project where state is managed by NgRX?

The problem I have the following:

  • User clicks on button to create a new item.
  • Modal window opens.
  • User fills out the form and clicks on Submit.
  • Dispatch an action, effects fires up and creates an item by sending HTTP request.
  • Now I need to close modal on success. How do I know when to close it either inside modal component or inside component that opened this modal?

One of the solutions I see right now is to return multiple actions from the effect, one that adds created item to the store, second one to close the modal. For this I should include some modal identifier in "Create" action to identify which modal to close after "Create$" effect completes, but this will make effect more complicated.

I can't believe there is no ready solution to this problem.

I use ngx-bootstrap for modals.

UPDATE: Seems like to make this work I need to store (state + reducer + effects + actions) open/closed status for each modal available in the application. But anyway, no existing solution?

2
What's wrong with this question? Why are those -1s? I'd appreciate comments on this. - Vladimir Prudnikov
Hi, Any solution to this problem? Stackblitz or any link would be of great help. - Manish Kumar
Yes, I found the solution myself that works great for me, I’ll create stackblitz a bit later. In short: I create a separate effects class for each modal which will hold modal instance and handle all related effects (open, submit, submit success and failure) and open/close its modal. - Vladimir Prudnikov

2 Answers

1
votes

I like to use an effect to handle the whole dialog flow, from opening the dialog to saving the entity and closing the dialog afterwards.

@Effect()
openDialog = this.actions.pipe(
  ofType(LoginActionTypes.OpenLoginDialog),
  exhaustMap(_ => {
    let dialogRef = this.dialog.open(LoginDialog);
    return dialogRef.afterClosed();
  }),
  map((result: any) => {
    if (result === undefined) {
      return new CloseDialog();
    }
    return new LoginDialogSuccess(result);
  }),
);

See Start using ngrx/effects for this for more info.

0
votes

You have to inject NgbActiveModal in the constructor of the component and call the method close(REASON) on it. So in the component you do:

import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';

export class ResetConfirmationComponent {

    constructor(
        public activeModal: NgbActiveModal
    ) { }
}

And in the template for that component:

<button type="button" class="btn btn-primary btn-default"
    (click)="activeModal.close('Reason for being closed ...')">
    Submit
</button>
<button type="button" 
    (click)="activeModal.dismiss('closed')">
    <span aria-hidden="true">&times;</span>
</button>

I don't know how you could close the dialog "on success". The open() method of NgbModal returns an Observable when close() was called on the NgbActiveModal (as opposed to calling dismiss() on it). If the operation was not successful, you should dispatch a failure action, and then re-open the dialog in another effect.

You can find a complete example repository showing the use of actions and effects: https://github.com/gflohr/ngbmodal-ngrx

Additional explanations and comments: http://www.guido-flohr.net/angular-bootstrap-modals-with-ngrx/