1

Consider the following case: A modal must be closed after an action succeeds. Would this be a viable solution:

@Component({
  selector: 'user-delete-dialog',
  templateUrl: './user-delete-dialog.component.html',
  styleUrls: ['./user-delete-dialog.component.scss']
})
export class UserDeleteDialogComponent implements OnInit {
  @Input() user: User;

  constructor(
    public dialog: NgbActiveModal,
    private store: Store
  ) { }

  ngOnInit(): void {
  }

  confirm() {
    this.store.dispatch(
      deleteUser({ 
        id: this.user.id, 

        onComplete: () => {
          this.dialog.close();
        },
  
        onError: () => {
          // Show errors ...
        }
      })
    );
  }
}

Another way would be subscribing to the main Actions stream, but listening to a context specific action globally just for the lifetime of the modal feels not right:

[...]
import { Actions } from '@ngrx/effects';
[...]

@Component(...)
class SomeComponent implements OnDestroy {
    destroyed$ = new Subject<boolean>();

    constructor(updates$: Actions) {
        updates$.pipe(
           ofType(UserActions.DELETE_SUCCESS),
           takeUntil(this.destroyed$)
        )
        .subscribe(() => {
           // close modal
        });
    }

    ngOnDestroy() {
        this.destroyed$.next(true);
        this.destroyed$.complete();
    }

    confirm() {
     this.store.dispatch(deleteUser({ id: this.user.id  }));
    }
}

Any ideas?

Thomas
  • 21
  • 2

2 Answers2

0

The best Practice is to listen to Actions in a central reducer. State is changed only in the reducer and components listen to state changes using selectors.

Consider you have a class UserState that has a boolean property called dialogOpen. Create a file called e.g. user.reducer.ts that contains the following

export const userReducer = createReducer<UserState>(initialState,
 on(UserActions.DELETE, (state) : UserState => { // code to delete the user}),
 on(UserActions.DELETE_SUCCESS, (state) : UserState => { // code when the delete is successful
     return {...state, dialogOpen: false}
 }),
 on(UserActions.DELETE_ERROR, (state): UserState => {/ code when the delete is errored})
)

on DELETE_SUCCESS you can set a boolean in the user state e.g. dialogOpen = false and check it in the modal component using a selector.

const getUserState = createFeatureSelector<UserState>('users')
export const getDialogOpen = createSelector(getUserState, state=> state.dialogOpen)

In the modal component you will have something like this

dialogOpen : Observable<boolean> = this.store.select(getDialogOpen);
Rasha Elsayed
  • 660
  • 1
  • 7
  • 22
0

The sense of the NgRx is to convert your application to the flow of events, so callbacks are not the solution. The right approach would include having a separate action for modal close event which can be emitted simultaneously with the other action, and component can subscribe to that action and provide an appropriate handler