Angular and NgRx
  • Introduction
  • Setup
  • 1. Create an application
  • 2. Create a home component
  • 3. Test HomeComponent
  • 4. Create event feature module
  • 5.Create AddAttendeeComponent
  • 6. Test AddAttendeeComponent
  • 7. Listen to child component events
  • 8. Add test for the event emitter
  • 9. Create EventListComponent
  • 10. Test EventListComponent
  • 11. Create EventService
  • 12. Test EventService
  • 13. Add simple NgRx spinner
  • 14. Test reducer
  • 15. Strongly type our store
  • 16. Update reducer tests
  • 17. Store dev tools
  • 18. Create selectors
  • 19. Create feature state
  • 20. Create effect
  • 21. Test an effect
  • 22. Use Entity Adapter
  • 23. Add attendee logic
  • 24. Router store
  • 25. Fix EventComponent tests
Powered by GitBook
On this page
  • 1. Add state folder and attendee actions
  • 2. Create a attendees reducer
  • 3. Add index.ts file to expose state logic from feature module
  • 4. Register feature state in the EventModule
  • 5. Examine the state tree in the devtools
  • StackBlitz Link

19. Create feature state

In this section we will make a new piece of feature state which will build on our knowledge from implementing the spinner state.

1. Add state folder and attendee actions

The best place to start when adding a new slice of state and the associated reducer, effects, selectors and tests is with the action creators. Starting with action creators helps be clear about what you want this section to be able to do and like tests becomes self documenting.

  • Create a state folder and a attendees sub-folder.

  • Create a attendees.actions.ts file.

  • Add the following actions to load attendees.

src/app/event/state/attendees/attendees.actions.ts
import { Action } from '@ngrx/store';
import { Attendee } from '../../../models';

export enum AttendeesActionTypes {
  LoadAttendees = '[Attendees Page] Load Attendees',
  LoadAttendeesSuccess = '[Attendees Page] Load Attendees Success',
  LoadAttendeesFail = '[Attendees Page] Load Attendees Fail'
}

export class LoadAttendees implements Action {
  readonly type = AttendeesActionTypes.LoadAttendees;
}

export class LoadAttendeesSuccess implements Action {
  readonly type = AttendeesActionTypes.LoadAttendeesSuccess;
  constructor(public payload: Attendee[]) {}
}

export class LoadAttendeesFail implements Action {
  readonly type = AttendeesActionTypes.LoadAttendeesFail;
  constructor(public payload: any) {}
}

export type AttendeesActions =
  | LoadAttendees
  | LoadAttendeesSuccess
  | LoadAttendeesFail;

2. Create a attendees reducer

  • Create a attendees.reducer.ts file in the state/attendees folder.

  • Add a interface called State describing this slice of state.

  • Add an initial state that implements this new State interface.

  • Add a reducer function that uses our initialState, AttendeesActionTypes and AttendeesActions types. We will come back and talk about this when we do effects in the next section.

src/app/event/state/attendees/attendees.reducer.ts
import { Attendee } from '../../../models';
import { AttendeesActions, AttendeesActionTypes } from './attendees.actions';

export interface State {
  attendees: Attendee[];
  loading: boolean;
}

export const intitalState: State = {
  attendees: [],
  loading: false
};

export function reducer(state = intitalState, action: AttendeesActions): State {
  switch (action.type) {
    case AttendeesActionTypes.LoadAttendees:
      {
      }

      break;

    default: {
      return state;
    }
  }
}

3. Add index.ts file to expose state logic from feature module

Index.ts files are like a public API for our feature state that re-exports everything we want to expose to our parts of our Angular application. Having an index.ts file helps other developers know what they should be able to access from this module.

In this index.ts file we will extend the feature State interface with our global State interface allowing us to have a more complete interface. We can not know what other lazy loaded state will have been loaded so this is not on the interface.

  • Create a index.ts file inside the event/state folder.

  • Import our global state name spaced to fromRoot.

  • Import our attendee state name spaced as fromAttendees.

  • Make a new EventState object that extends the root state.

  • Make a ActionReducerMap that is a Map of all the reducers in this feature of which we have only one.

src/app/event/state/index.ts
import { ActionReducerMap } from '@ngrx/store';

import * as fromRoot from './../../state/state';
import * as fromAttendees from './attendees/attendees.reducer';

export interface EventState {
  attendees: fromAttendees.State;
}

export interface State extends fromRoot.State {
  event: EventState;
}

export const reducers: ActionReducerMap<EventState> = {
  attendees: fromAttendees.reducer
};

4. Register feature state in the EventModule

  • Register StoreModule.forFeature in the EventModule and pass in our reducer map from the index.ts file.

  • We need to name each piece of state even if it is a map of one or more reducers. This means our state tree will start with properties named after each feature state slice and one for each root state slice like below.

{
    spinner: {...}
    event: {...}
    someOtherFeatureState: {...}
}
src/app/event/event.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';

import { EventComponent } from './containers/event/event.component';
import { AddAttendeeComponent } from './components/add-attendee/add-attendee.component';
import { EventListComponent } from './components/event-list/event-list.component';
import { StoreModule } from '@ngrx/store';
import { reducers } from './state';
@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild([{ path: '', component: EventComponent }]),
    ReactiveFormsModule,
    HttpClientModule,
    StoreModule.forFeature('event', reducers)
  ],
  declarations: [EventComponent, AddAttendeeComponent, EventListComponent]
})
export class EventModule {}

5. Examine the state tree in the devtools

  • Open browser and go to event page

StackBlitz Link

Previous18. Create selectorsNext20. Create effect

Last updated 6 years ago

Duncanhunter - Angular And Ngrx Demo App - StackBlitzStackBlitz
Web Link: Link to the demo app running in StackBlitz
Logo
Event page of running app showing state tree with feature state