Between my different Angular projects, notifying users after certain events take place needed consistency.  Users typically require a few types of notifications, error, warning, and informational messages.  Due to the different projects for displaying notifications, I required a generic store of messages that could be consumed by different applications.

For my purposes, I required this generic store of messages to be used in an Ionic Application and another applied in an Angular Material app.  Both of these frameworks provide a toast type of notification for the user, so rendering the UI framework’s specific notification types differ slightly in their implementation.

Goals

  1. Create a generic store of messages within NgRx
  2. Consume Messages in an App
  3. Display the UI Framework’s Toast Type Message

Create a Generic Store of Messages within NgRx

The notification type consists of three types.

Notification Type

My model includes an id, message, type, and nextActions.

Notification Model

nextActions allows me to dispatch dependent actions within the ApplicationStore.  In the event I close the notification, there could be a series of actions I’d need to dispatch afterward.  Per the effect I created for the NotificationStore, one of these effects removes the notification from the store.  I don’t want to limit myself to just removing the notification because I foresee an instance where the user needs to acknowledge they read the notification before proceeding to the next step and an action needs to be dispatched.

Free Your Developers

Nx Monorepo Starter alleviates developers from re-inventing deployments on popular Google Cloud Services, standardizes on libraries, and saves time for scaffolding projects.

View on Gumroad

Next, actions dispatched need to add, remove, clear, and watch notification as they enter the NotificationStore.  I created a few actions to be more specific to the notification type so its clear to other developers the type of notification to display.

Notification Actions

The reducer listens for three actions, ADD_NOTIFICATION, REMOVE_NOTIFICATION, CLEAR_NOTIFICATIONS.

Notification Reducer

In the reducer, the messages insert at the end of the array. In the selector, I select the next message in a First In First Out method choosing the first message in the array.

Notification Selector

Notification Effects

The notification effects watch the Notification Store as messages fill.  The message type determines which action dispatches.

My application can now watch for the different notifications as they add and remove.  I configure watching in the ApplicationStoreModule.

Consume Messages within the ApplicationStore

My apps include an ApplicationStore for the purposes of handling application wide actions and events.  Notifications sprinkle throughout the application's different modules, so I orchestrate the display of notifications within the ApplicationStore.

I need the application to start watching for notifications when messages add to the store.  My NotificationStoreModule is a feature module, so it doesn't initially pick up the INIT and INIT_ROOT_EFFECTS actions (not sure if this can be corrected, let me know otherwise).  For this case, I decided to dispatch the watch for notifications in an APP_INITIALIZER with my ApplicationStoreModule.

ApplicationStore Effects

The ApplicationStoreEffects watch notifications in a stream from the store.  As notifications fill the store until it empties, UI notifications display to the user one at a time with a 500 millisecond delay.

The NotificationActions dispatch from different components or within effects with services that fail or succeed notifying the user.

Exercise has been updated notification displays after a user saves

Below shows an example of an effect dispatching these events when a Firebase service updates a record then displaying the notification above.

Summary

User notifications differ between application UI frameworks.  The NotificationStore's responsibility stores messages dispatched from effects, services, and components which I wanted a universal mechanism to store and dispatch different messages.