- Settings:
Page
Normal
Plain layout without fancy styles
Font
Normal
Large fonts
Very large fonts
Colour
Normal
Restful colour scheme
Light text on a dark background

Note: user account creation on this site has been disabled.

Programming, speculative fiction, science, technology
Powered by Drupal, an open source content management system
Scope
Include Children
If you select a term with children (sub-terms), do you want those child terms automatically included in the search? This requires that "Items containing" be "any."
Categories

Everything in the Events vocabulary

"Events" is used for: Convention Post, Page, Story.

People mentioned in the articles

"People" is used for: Page, Convention Post, Story.

Themes mentioned in the article

"Themes" is used for: Page, Convention Post, Story.
Skip to top of page

Angular with Redux, Store, and Effects: an introduction

There are many tutorials on how to get started with the Redux pattern in Angular 2, and how to use its essential concepts like store or effects. But often you'll find that those tutorials don't work for you -- maybe the author omitted something that was self-explanatory to them, or maybe (and that's a fact) Redux-related packages in npm change so often that the code in the tutorials from a few months ago does not compile anymore. So let's throw in another tutorial that will be obsolete just as soon, shall we?

In this tutorial we'll build a very simple application that will allow us to pick out a "cat alarm", or a mode in which we would like to be woken up by our cat. It will have only one thing, a button that will let us cycle between four cat alarm modes: "Meowing loudly for food", "Chasing a rattling toy across the floor", "Repeatedly jumping at your bedroom doorknob", and "Vomiting on the carpet".

It will demonstrate such Redux concepts as action, reducer, store, state (what? Store AND state? Two five-letter words that differ only by two letters? What evil committee named these things?), oh, and effect.

To create a minimal Angular 2+ (including 4, 5, or whatever the current version is), let's do something like what this Microsoft tutorial for Angular 2 application recommends. No, you don't have to read the whole tutorial. It's just that maybe you would like to read actual documentation written by people who are paid to write such things, haha.

Let's install angular-cli on our machine, if we haven't already, change to our favorite directory, and run

ng new wakeup-call -sd src/client --minimal --style scss

cd wakeup-call

This application will have a very simple server, based on Node.js framework Express. It will be here just to serve some hardcoded JSON. We only need it so we could demonstrate the "effect" of calling the API. So let's install it.

npm i express body-parser --save

Then let's launch Visual Studio Code, and open the application folder. Under src directory let's create a server directory, and in the server directory let's create an index.js file. Let's put this code in it:

const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const routes = require('./routes');

const root = './';
const port = process.env.PORT || '3000';
const app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(root, 'dist')));
app.use('/api', routes);
app.get('*', (req, res) => {
  res.sendFile('dist/index.html', {root});
});

app.listen(port, () => console.log(`API running on localhost:${port}`));

Then, in the same directory (src/server, let's create a routes.js file, and put this code in it:

const express = require('express');
const router = express.Router();

const wakeupModes = [
    {"id": 1, "wakeup_mode": "Meowing loudly for food"},
    {"id": 2, "wakeup_mode": "Chasing a rattling toy across the floor"},
    {"id": 3, "wakeup_mode": "Repeatedly jumping on your bedroom doorknob"},
    {"id": 4, "wakeup_mode": "Vomiting on the carpet"}
 ];

router.get('/wakeupMode/:id', (req, res) => {
    const ourId = req.params["id"];
    var elem = wakeupModes.find( x => x.id == ourId);
    res.send(200, elem);
   });

router.get('/wakeupModes', (req, res) => {
    res.send(200, wakeupModes);
   });


module.exports=router;

And now for a moment I'll just send you to the afore-mentioned Microsoft tutorial for creating an Angular 2 application with Express.js server, where you should follow steps 8 and 9 of the tutorial to create the configuration and launch the application in the debugging mode. It wouldn't make sense for me to just copy-paste what Microsoft documentation says, would it?

Now that the application has launched, enter this URL in the browser:

http://localhost:3000/api/wakeupModes/1

You should see:

id	1
wakeup_mode	"Meowing loudly for food"

And if you enter this URL in the browser

http://localhost:3000/api/wakeupModes

you should see all four wakeup modes.

That's it as far as the server goes. We have a simple API with two routes.

Building the frontend

Now we can build the frontend for this application. It will call the API we created above. We don't have to use Material Design, but everybody uses it these days, so why not throw it in?

Let's install Material Design. In the command line, cd to the wakeup-call directory if you are not there already, and run this:

npm install --save @angular/material @angular/cdk

Now let's use it. The initial creation of the app created an app directory with some files in it, among them app.module.ts. At the top of the app.module.ts file, below the import { NgModule } line, put:

import {MatButtonModule} from '@angular/material';

Add MatButtonModule it to the imports: array. For example, like this:

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    MatButtonModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})

Then, if you want a "fancier" Material Design theme, one that would add a touch of color to those otherwise stark plain buttons, you can put this in the styles.scss file of your app:

@import "~@angular/material/prebuilt-themes/indigo-pink.css";

And now, back to cat wakeup alarms.

First we'll add a button to the component's template page. This button will let us cycle between three states: "Meowing loudly for food", "Chasing a rattling toy across the floor", and "Repeatedly jumping at your bedroom doorknob", and "Vomiting on the carpet".

If creating your app created a src/app/app.component.html, open it. If there is no such file, create it.

For now there will be just the button that says "Get another way". It won't do anything yet. In the app.component.html, if it already existed, remove everything and put this code:

<div class="cat-alarm" style="text-align:center">
    <h1>
      Welcome to {{ title }}!
    </h1>

  <h2>In what manner would you like to be woken up by a cat? </h2>
    <button mat-raised-button class="mat-primary">Try another way</button>
</div> 

For CSS styling, create 'app/src/app.component.scss' first. Let's create some minimal styles, just so we won't have that ugly Times Roman splattered all over the page. Let's put these lines in it:

div.cat-alarm {
    font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif
}

Now let's open app.component.ts file. This is a boilerplate component class. One of its fields will be template, and it will have a bunch of boilerplate HTML in it. Replace the template: and all that HTML with this:

templateUrl: './app.component.html',

and replace

styles: []

with

styleUrls: ['./app.component.scss']

So, app.component.ts should have this in it now:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']	
})
export class AppComponent {
  title = 'Cat Alarm';
}

Now we can try to run whatever little is there, just to make sure it runs.

Let's build it. At the command prompt (where we are still in the wakeup-call directory, run

ng build

Then relaunch the application from Visual Studio Code.

Navigate to localhost:3000 (presumably Visual Studio Code will run this app on the port 3000. If it runs on a different port, it will tell you at the bottom).

You should see this page:

You can see how the source code of the whole application looked at that point by browsing the source code on Github. This link leads to the snapshot of the source tree at the initial commit.

Starting out with Redux: calling the server API and displaying the result

Let's install @ngrx/store.

In the shell in the project top level directory, run

npm install @ngrx/store

Before we do anything, let's define our "model". While this application doesn't, strictly speaking, conform to MVC (model-view-controller) architecture (it doesn't have controllers), it is convenient to have a model class that encapsulates the fields that are being passed between the frontend and the backend. In fact, we already have a model in the backend: the wakeupModes array in the routes.js file is a collection of model instances. Let's create one for the frontend.

In the src/app directory, add this a file named WakeupMode.ts. Put this code in it:

export class WakeupMode {
    id: number;
    wakeup_mode: string;
}

Now we will start creating actions and reducers.

Right-click the "src/app" directory in Visual Studio Code, and create a new file. You can call it CatAlarmActions.ts. Put this code in it:

import { Action } from '@ngrx/store';
import { WakeupMode } from './WakeupMode';
export const GET_DEFAULT_ALARM_MODE = 'GET_DEFAULT_ALARM_MODE';
export const GET_DEFAULT_ALARM_MODE_SUCCESS = 'GET_DEFAULT_ALARM_MODE_SUCCESS';

export class GetDefaultAlarmModeAction implements Action {
    readonly type = GET_DEFAULT_ALARM_MODE;
    constructor(public payload: WakeupMode) {}
  }

export class GetDefaultAlarmModeSuccessAction implements Action {
    readonly type = GET_DEFAULT_ALARM_MODE_SUCCESS;
    constructor(public payload: WakeupMode) {}
  }

This file defines two actions, GetDefaultAlarmModeAction and GetDefaultAlarmModeSuccessAction action. GetDefaultAlarmModeAction is the action of contacting the server to get the default cat alarm mode. GetDefaultAlarmModeSuccessAction is the action of getting a successful response from a server. Or perhaps more accurately, it's an action that tells the frontend to process the successful response from the server.

These actions don't do anything by themselves, they merely communicate to certain parts of code that something needs to be done, and often provide the data to do it with.

Creating an effect: retrieving data from the server

Our initial requirement is for the frontend to call the server at the time when the component is being loaded, and retrieve a cat alarm wakeup mode. Usually, at least with Angular 1, the piece of frontend code that called the backend was in a service. It was not uncommon to call it a data service. But now that effects exist, people seem to be calling this construct an Effect. Oh well then. We'll add an effect. But first, we need to install @ngrx/effects.

In the shell in the project top level directory (wakeup-call directory, run

npm install @ngrx/effects

Now we'll create the simplest of effects, one that calls the server and retrieves some data. The data will be the initial, default cat alarm wakeup mode, and it will appear on the web page when the web page is loaded. Of the four wakeupModes that we have in the backend, we will arbitrarily decree that the default one is the one with id=2.

In the src/app directory, let's create a file CatAlarmModeEffect.ts, and put this code in it:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Actions, Effect } from '@ngrx/effects';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/of';

import { GetDefaultAlarmModeAction } from './CatAlarmActions';

@Injectable()
export class CatAlarmModeEffect {
  constructor(
    private http: HttpClient,
    private actions$: Actions
  ) { }

  @Effect() getSkills$ = this.actions$
      // Listen for the 'GET_DEFAULT_ALARM_MODE' action
      .ofType('GET_DEFAULT_ALARM_MODE')
      .map((action: GetDefaultAlarmModeAction) => action.payload)
      // Map the payload into JSON to use as the request body
      .switchMap(payload => 
        this.http.get('/api/wakeupMode/' + payload.id)
        // If successful, dispatch success action with result
        .map(res => ({ type: 'GET_DEFAULT_ALARM_MODE_SUCCESS', payload: res }))
        // If request fails, dispatch failed action
        .catch(() => Observable.of({ type: 'GET_DEFAULT_ALARM_MODE_FAILED' }))
      );
}

(By the way, for those dealing with the changes in ngrx/store Action type that removed the payload property and caused all the tutorials to break, the trick, as you see, is to have your own type that derives from Action, and put the payload property in it. I got this from ngrx/store migration instructions. Many online ngrx/store and ngrx/effects tutorials, written prior to late 2017, won't work now because the payload field was removed from the Action type (supposedly for type safety considerations). Thus we first need to define a class GetDefaultAlarmModeAction, which has the payload field.)

Using the ngrx/effects module requires "telling" the application about it; specifically, we need to inject it as a provider in app.module.ts. It also requires injecting the ngrx/store as a provider. So let's make the app.module.ts look like this:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { EffectsModule } from '@ngrx/effects';
import { MatButtonModule } from '@angular/material'; 
import { StoreModule } from '@ngrx/store';

import { CatAlarmModeEffect } from './CatAlarmModeEffect';

import { AppComponent } from './app.component';


@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    StoreModule.forRoot({
      //This is where the reducer function will go when we write it
  }),
    BrowserModule,
    MatButtonModule,
    EffectsModule.forRoot([CatAlarmModeEffect]),
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

At this point, if you build and run the application, it should build and run. It won't do anything yet, however. That will come next.

Dispatching an action

The actions by themselves do nothing, they are just passive bits of information passed between pieces of code. For an action to accomplish something, it needs to be dispatched. So let's write code that will dispatch it. Which part of the application will dispatch it? For an application this simple, the dispatching code can be in the component itself, i.e. in the app.component.ts.. Oh, but we haven't really talked about what's supposed to be in the app.component.ts., have we? The application generated it for us, and it's been lying fallow.

So let's populate it.

First, what does it need to have? It needs to keep track of the current wakeup mode. For now, the current wakeup mode will be the default mode that we get from the server when the application is launched. Later, we'll add the ability for the user to change the wakeup mode, so the current wakeup mode will be the one selected by the user. This will be the property of the component. For the sake of simplicity, let's call it wakeupMode, and its type will be WakeupMode that we defined above in WakeupMode.ts file. In other words, it will be the model of our application.

In addition to that property, let's add a whole lot of other things to app.component.ts, and we'll explain what they are in a moment.

import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import { GET_DEFAULT_ALARM_MODE, GET_DEFAULT_ALARM_MODE_SUCCESS } from './CatAlarmActions';
import { WakeupMode } from './WakeupMode';

interface WakeupModeState {
  currentWakeupMode: WakeupMode;
}


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})

export class AppComponent {
  title = 'Cat Alarm';
  wakeupMode: WakeupMode;

  constructor(private wakeupModeStore: Store) {    
    wakeupModeStore.select('currentWakeupMode').subscribe(wMode => {
      this.wakeupMode = wMode;
    });
  }

  ngOnInit() {
    this.wakeupModeStore.dispatch({ type: GET_DEFAULT_ALARM_MODE, payload: { id: 2 } });
   }    
}

If we look at the constructor, it is being passed a Store object wakeupModeStore. In the ngOnInit(), the wakeupModeStore dispatches an action of the type GET_DEFAULT_ALARM_MODE, which, as we know, tells the effect code to contact the server and get the default cat alarm wakeup mode. Its payload has id: 2. This id (as we saw in routes.js) corresponds to "Chasing a rattling toy across the floor".

But what is this mysterious wakeupModeStore.select('currentWakeupMode') ? Don't ask me, I only poked this code until it worked. The wakeupModeStore "selects" a part of itself that is currentWakeupMode (whose type is WakeupMode), and subscribes to it. We know that currentWakeupMode is somehow accessible to wakeupModeStore, because at the top of the file we have this definition:

interface WakeupModeState {
  currentWakeupMode: WakeupMode;
}

and in the constructor the wakeupModeStore variable is declared like this:

private wakeupModeStore: Store

So wakeupModeStore is a Store of WakeupModeState's. A store of state. Because it was not enough to have a mysterious, ill-defined "store" concept, now we also have a "state" concept. Store. State. Two words of five letters, differing by only two letters. If there was ever an indication that Redux was created by an evil committee, this would be it.

And yet from what we heard about the purpose of Redux being state management, it kind of makes sense -- with some stretch of imagination. Redux manages the state of the application. The state describes the current snapshot of the application. It describes everything that is there to know about the application at the current time. It makes sense to call it a state. And our toy application's state is described entirely by the currently selected wakeup mode. Thus, the interface WakeupModeState contains a WakeupMode object currentWakeupMode.

The mysterious Store is something that dispatches actions and subscribes to the observables, and does the right thing with their values. In other words, it does everything. It orchestrates passing of the information (via Actions between various parts of the application. In the ngOnInit() it dispatches a GET_DEFAULT_ALARM_MODE action with a payload {id: 2}, and since ngOnInit() is executed at the beginning of component lifecycle, that's how the wakeup mode's initial value is populated. When the store dispatches this action, the getSkills$ effect from CatAlarmModeEffect "kicks in" -- remember, it listens for this type of action -- and calls the appropriate API URL from the server.

You can build the application and run it now. What we have done so far is we have dispatched an action to the server. We are not doing anything with the return value yet: we haven't written the code for that yet. That will come next. But for now, you can verfiy that the frontend is actually contacting the server by opening Chrome Developer Tools (or equivalent tools in your browser), clicking the Network tab, reloading the page, and seeing the network request the brower makes to the server. Alternatively, if you are using an IDE (such as Visual Studio Code), you can put a breakpoint in routes.js method router.get('/wakeupMode/:id', (req, res)... , and you will see that this method is actually getting called, and the id parameter that's being passed to it is 2.

Adding reducers: processing the value that the server returns

By now you would think we have written enough boilerplate code that does nothing but pushes the same bit (no, not literally a bit) of information around. Shouldn't all this contraption work by now? Noooo! Something else is missing. Reducers. Because remember, in Redux applications the state is immutable. The object representing the state is not allowed to change. So instead of modifying it, we put a new one in its place. That's what a reducer will do. This is known as "reducing" the state. Why reducing? Well, maybe before the Action happened, it was too complicated, and we are making it simpler. Ha. Has it ever happened that while interacting with an application, you made something simpler rather than created a mess?

But this is called Redux, so we better start reducing.

In the src/app directory let's add a file CatAlarmReducers.ts. Let's paste this code in it:

import { Action } from '@ngrx/store';
import { WakeupMode } from './WakeupMode';
import { GET_DEFAULT_ALARM_MODE_SUCCESS, GetDefaultAlarmModeSuccessAction } from './CatAlarmActions';

export function alarmModeReducer(state: WakeupMode = {id: 1, wakeup_mode: "Meowing loudly for food"}, 
        action: GetDefaultAlarmModeSuccessAction) {
    switch (action.type) {
        case GET_DEFAULT_ALARM_MODE_SUCCESS:
            const alarmModeFromBackend = Object.assign({}, state, {
                id: action.payload.id,
                wakeup_mode: action.payload.wakeup_mode
            });
            return alarmModeFromBackend;            
        default:
            return state;
    }
}

The more interesting points about this are:

  • If no state is passed to the reducer, we pass it an initial state, {id: 1, wakeup_mode: "Meowing loudly for food"}.
  • We also pass an action of the type GetDefaultAlarmModeSuccessAction.
  • Then, in the switch statement, we do things depending on the action type. But, you say, the action is of the GetDefaultAlarmModeSuccessAction type, so why the switch statement? Well, at the moment the reducer can only process this type of action; we don't have others. But we'll add others in the future, I promise!
  • And since state in Reduxx pattern is supposed to stay immutable, we use Object.assign to create a new state by assigning a combination of the old state and a new WakeupMode to an empty object ({}).

Let's add some lines to app.module.ts to let it know about this reducer. Under all the import statements, let's add another one:

import { alarmModeReducer } from './CatAlarmReducers';

In

StoreModule.forRoot({
      //This is where the reducer function will go when we write it
}),

replace the comment with this line:

currentWakeupMode: alarmModeReducer

So app.module.ts will now look like this:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { EffectsModule } from '@ngrx/effects';
import { MatButtonModule } from '@angular/material'; 
import { StoreModule } from '@ngrx/store';

import { CatAlarmModeEffect } from './CatAlarmModeEffect';

import { AppComponent } from './app.component';


@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    StoreModule.forRoot({
       currentWakeupMode: alarmModeReducer
  }),
    BrowserModule,
    MatButtonModule,
    EffectsModule.forRoot([CatAlarmModeEffect]),
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

The application should build and run at this point. But to see the effect in action, we will need one more thing: updating the template.

Updating the template to display the data

Now, if we reload the web page, the data will be retrieved from the backend, but we still need to display it in the web page. In the app.component.html file, under the <button>...</button> element, add this line:

{{ wakeupMode.id }} : {{ wakeupMode.wakeup_mode }}

app.component.html should look like this now:

<div class="cat-alarm" style="text-align:center">
    <h1>
      Welcome to {{ title }}!
    </h1>

  <h2>In what manner would you like to be woken up by a cat? </h2>
    <button mat-raised-button class="mat-primary">Try another way</button>
    <div>{{ wakeupMode.id }} : {{ wakeupMode.wakeup_mode }}</div>
</div> 

Build and launch the application again. Now, when you reload the page, under the button you should see this:

2 : Chasing a rattling toy across the floor

The page might look at lot like this:

So the web page is displaying the option #2 from routes.js. QED! With only a couple hundred lines of code we have accomplished what in plain Javascript and HTML you could do in some 10 lines! But it's all supposed to be worth it later, because it will give structure to the application when we add tons of new functionality to it, right? And it only took a novella-length article ot describe it!

By the way, the button doesn't work yet. We will later make it work when we write a new novella in this series. But... this novella is not even finished. There was that catch statement, and we are not doing anything with it. We should do something with it! If the user somehow manages to pass an invalid WakupMode value (we are not letting them do that here, but you know those tricksy users), they should get a nice error message. So first, we should handle errors.

Handling errors from effects

To create an error condition, let's have the frontend call the server with a request for a non-existent value. First, let's modify the server-side code so that it would recognize when it's being asked for a non-existent value, and respond with an error.

In routes.js file, modify this function

router.get('/wakeupMode/:id', (req, res) => {
    const ourId = req.params["id"];
    var elem = wakeupModes.find( x => x.id == ourId);
    res.send(200, elem);
   });

like this:

router.get('/wakeupMode/:id', (req, res) => {
    const ourId = req.params["id"];
    var elem = wakeupModes.find( x => x.id == ourId);
    if (!elem) {
        res.status(404).send(`The cat doesn't know what ${ourId} means. The cat can only count to ${wakeupModes.length}.`)
    }
    res.send(200, elem);
   });

That's catspeak for "Array index out of range". If the server can't find an element with a given ID, it will return a 404 status.

To test it, let's hardcode the id to 5 in the frontend, because currently there is no other way to cause an error condition. In app.component.ts, in ngOnInit(), let's replace the value of id with 5, so that now this function will look like this:

  ngOnInit() {
    this.wakeupModeStore.dispatch({ type: GET_DEFAULT_ALARM_MODE, payload: { id: 5 } });
   } 

ng build and run the application. Now, when you reload the page, if you have the browser's developer tools open, in the console you'll see a 404 returned from the server.

To handle this error, we have the catch method call in CatAlarmModeEffect.ts. What should we put in it? What is in it currently won't work, because while we dispatch an action, there is no reducer to process that action.

We can explore this catch method a little first. It's supposed to return an Observable. First, we could rewrite it this way:

.catch(() => {
  console.log(`Server returned a status ${e.status}, message ${e.error}`);
  return Observable.empty();
});

If you ng build and run the application now, you'll see the error message returned from the server in the console. But logging to the console is probably not entirely the error handling we want. We want to display a nice message to the user. In our original code, the catch method dispatched an action. We'll go back to that, and we'll write a reducer that will take that action and transform it appropriately, eventually displaying a message on the page.

Going back to the original catch method, it dispatches an action. What should be the payload of this action? It probably shouldn't have id in it, because when an error occurs on the server, it might not return a record, thus there won't be a meaningful id to speak of. Instead, this action should contain information about the error.

Let's change the catch method to this

.catch((e) => {
  Observable.of({ type: 'GET_DEFAULT_ALARM_MODE_FAILED', payload: e })
});

It dispatches an action with the error as a payload. What should be the type of this error object?

Let's define the error "model". In src/app, let's create a new file and call it EffectErrors.ts. Put this code snippet in this file:

export class EffectError {
    status: number;
    error: string;
}

status and error are fields in the response object that the server returns. There are more of them, but for the sake of simplicity we may not be interested in all of them, just the status code (such as 404), and the error message. So our model will contain just those two, and we will discard the rest.

Now let's create an additional Action type for passing errors around. In CatAlarmActions.ts, let's add a new action type and a new Action. Near the top of the file, under other export const statements, add this statement:

export const GET_DEFAULT_ALARM_MODE_FAILED = 'GET_DEFAULT_ALARM_MODE_FAILED';

At the bottom of the file, add this snippet:

export class GetDefaultAlarmModeFailureAction implements Action {
  readonly type = GET_DEFAULT_ALARM_MODE_FAILED;
  constructor(public payload: EffectError) {}
}

At the very top of the file, under import { Action }, add this:

import { EffectError} from './EffectErrors';

The file should look like this now:

import { Action } from '@ngrx/store';
import { EffectError} from './EffectErrors';
import { WakeupMode } from './WakeupMode';
export const GET_DEFAULT_ALARM_MODE = 'GET_DEFAULT_ALARM_MODE';
export const GET_DEFAULT_ALARM_MODE_SUCCESS = 'GET_DEFAULT_ALARM_MODE_SUCCESS';
export const GET_DEFAULT_ALARM_MODE_FAILED = 'GET_DEFAULT_ALARM_MODE_FAILED';

export class GetDefaultAlarmModeAction implements Action {
    readonly type = GET_DEFAULT_ALARM_MODE;
    constructor(public payload: WakeupMode) {}
  }

export class GetDefaultAlarmModeSuccessAction implements Action {
    readonly type = GET_DEFAULT_ALARM_MODE_SUCCESS;
    constructor(public payload: WakeupMode) {}
  }

export class GetDefaultAlarmModeFailureAction implements Action {
  readonly type = GET_DEFAULT_ALARM_MODE_FAILED;
  constructor(public payload: EffectError) {}
}

Now we need to make the store and the state aware of those actions. In app.component.ts, add this line below all the import statements:

import { EffectError} from './EffectErrors';

Add another property to the component, called effectError. Paste this line before the constructor line:

effectError: EffectError;

Modify interface WakeupModeState so it would look like this:

interface WakeupModeState {
  currentWakeupMode: WakeupMode;
  currentError: EffectError;
}

We need to subscribe to the observable associated with currentError. We can add a snippet to the bottom of the constructor:

    wakeupModeStore.select('currentError').subscribe(eError => {
      this.effectError = eError;
      console.log(`Server returned a status ${eError.status}, message ${eError.error}`);      
    });

but we probably want the error to be displayed in a more user-accessible way than logging it to console. So let's display it in a snackbar -- a small pop-up bar at the bottom of the page that will go away on its own. But it should only display the snackbar if the status returned from the server is not 200 "OK". For that purpose, let's make a helper enum that would contain some HTTP status codes.

In src/app directory, create a new file called HttpStatuses.ts. Put this code in it:

export enum HttpStatus {
    OK = 200,
    NotFound = 404,
    InternalServerError = 500
}

In app.component.ts, add this line below all the import statements:

import { HttpStatus } from './HttpStatuses';

Now let's make the constructor look like this:

  constructor(private wakeupModeStore: Store,
    public snackBar: MatSnackBar) {    
    wakeupModeStore.select('currentWakeupMode').subscribe(wMode => {
      this.wakeupMode = wMode;
    });

    wakeupModeStore.select('currentError').subscribe(eError => {
      this.effectError = eError;
      if (eError.status != HttpStatus.OK) {
        snackBar.open(eError.error, "", {
          duration: 3000
        });
      }
      
    });    
   }

duration: 3000 means that after 3000 milliseconds the snackbar with the error message will vanish.

MatSnackBar comes from the Angular Material module, and needs to be imported at the top of the file. Add this line below the import statements:

import {MatSnackBar} from '@angular/material';

app.module.ts also needs to be modified to add proper import statements. It needs to look like this:

    
import { BrowserModule } from '@angular/platform-browser';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { EffectsModule } from '@ngrx/effects';
import {MatButtonModule, MatSnackBarModule} from '@angular/material'; 
import { StoreModule } from '@ngrx/store';

import { CatAlarmModeEffect } from './CatAlarmModeEffect';
import { alarmModeReducer, errorReducer } from './CatAlarmReducers';

import { AppComponent } from './app.component';


@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    StoreModule.forRoot({
      currentWakeupMode: alarmModeReducer,
      currentError: errorReducer
  }),
    BrowserModule,
    BrowserAnimationsModule,
    MatButtonModule,
    MatSnackBarModule,
    EffectsModule.forRoot([CatAlarmModeEffect]),
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Last, we need to add a reducer to process the Action of the type GET_DEFAULT_ALARM_MODE_FAILED. As app.module.ts StoreModule.forRoot configuration indicates, the reducer for errors is called errorReducer. That's just what we decided to call it; it can be anything. At the bottom of the CatAlarmReducers.ts file, add this function:

export function errorReducer(state: EffectError = {status: 200, error: "OK"}, 
        action: GetDefaultAlarmModeFailureAction) {
    switch (action.type) {
        case GET_DEFAULT_ALARM_MODE_FAILED:
            const errorFromBackend = Object.assign({}, state, {
                status: action.payload.status,
                error: action.payload.error
            });
            return errorFromBackend;            
        default:
            return state;
    }
}

And that should be it. Now when you ng-build, run your application, and reload the page, you should see a snackbar at the bottom of the page with the above-mentioned error message. It should look like this:

You can see the snapshot of the source tree at this point by here on Github.

Using async pipe

Earlier in app.component.ts we explicitly subscribed to the Observable of WakeupMode:

    wakeupModeStore.select('currentWakeupMode').subscribe(wMode => {
      this.wakeupMode = wMode;
    });

Since this subscription does not do anything with the data it gets from observable except display it, we can simplify this statement. We can replace this whole snippet with

this.wakeupMode$ = wakeupModeStore.select('currentWakeupMode');

In app.component.html we can replace the line

    <div>{{ wakeupMode.id }} : {{ wakeupMode.wakeup_mode }}</div>

with

    <div *ngIf="wakeupMode$ | async as wakeupMode">{{ wakeupMode.id }} : {{ wakeupMode.wakeup_mode }}</div>

For that, we also need to change this statement above

wakeupMode: WakeupMode;

to

wakeupMode$: Observable;

Usage of *ngIf with async pipe and as is explained very well in this article. It also explains why it's not a good idea to write, for example

    <div">{{ (wakeupMode$ | async)?.id }} : {{ (wakeupMode$ | async)?.wakeup_mode }}</div>

-- it is because that could create unnecessary subscriptions to the wakeupMode$ observable, resulting in unnecessary trips to the backend. So *ngIf with async pipe and as is the way to go.

You can see the snapshot of the source tree at this point by here on Github.