Skip to content

Latest commit

 

History

History
509 lines (325 loc) · 13.2 KB

README.NGRX.md

File metadata and controls

509 lines (325 loc) · 13.2 KB

Angular 5 + CLI + NGRX Schematics

mkdir -p ~/Sites/angular/ngrx && cd ~/Sites/angular/ngrx
npm install -g @angular/cli

Let's create a new App

ng new ngrxApp --routing --style scss

cd ngrxApp

Optionally use Yarn for Angular CLI

ng set --global packageManager=yarn

Auth module

ng g module components/Auth --routing --flat false

# then you will see:

create src/app/components/auth/auth-routing.module.ts
create src/app/components/auth/auth.module.ts

Auth module - Landing component

ng g component components/auth/components/Landing -m components/auth/auth.module.ts --spec

# then you will see:

create src/app/components/auth/components/landing/landing.component.scss
create src/app/components/auth/components/landing/landing.component.html
create src/app/components/auth/components/landing/landing.component.spec.ts
create src/app/components/auth/components/landing/landing.component.ts
update src/app/components/auth/auth.module.ts

Auth module - Signup component

ng g component components/auth/components/Signup -m components/auth/auth.module.ts --spec

# then you will see:

create src/app/components/auth/components/signup/signup.component.scss
create src/app/components/auth/components/signup/signup.component.html
create src/app/components/auth/components/signup/signup.component.spec.ts
create src/app/components/auth/components/signup/signup.component.ts
update src/app/components/auth/auth.module.ts

Auth module - Login component

ng g component components/auth/components/Login -m components/auth/auth.module.ts --spec

# then you will see:

create src/app/components/auth/components/login/login.component.scss
create src/app/components/auth/components/login/login.component.html
create src/app/components/auth/components/login/login.component.spec.ts
create src/app/components/auth/components/login/login.component.ts
update src/app/components/auth/auth.module.ts

tree

|____app.component.html
|____app-routing.module.ts
|____app.component.scss
|____app.component.spec.ts
|____app.module.ts
|____app.component.ts
|____components
| |____auth
| | |____components
| | | |____landing
| | | | |____landing.component.spec.ts
| | | | |____landing.component.ts
| | | | |____landing.component.html
| | | | |____landing.component.scss
| | | |____signup
| | | | |____signup.component.ts
| | | | |____signup.component.spec.ts
| | | | |____signup.component.html
| | | | |____signup.component.scss
| | | |____login
| | | | |____login.component.spec.ts
| | | | |____login.component.ts
| | | | |____login.component.scss
| | | | |____login.component.html
| | |____auth-routing.module.ts
| | |____auth.module.ts

Auth module routing and App module routing

Landing works!

Login works!

Signup works!

ng serve

chunk {auth.module} auth.module.chunk.js
chunk {inline} inline.bundle.js
chunk {main} main.bundle.js
chunk {polyfills} polyfills.bundle.js
chunk {styles} styles.bundle.js
chunk {vendor} vendor.bundle.js

Let's create a sharable Material Module

yarn add @angular/material @angular/cdk @angular/animations
ng g module shared/Material --flat false

# then you will see:

create src/app/shared/material/material.module.ts

Play with Card Content Container and [routerLink] parameters

Now we have routes configured and a place to render them, but how do we navigate?

Theming our Angular Material app

Let's define our User Model

ng g class models/user

Forms

Reactive forms:

yarn add @angular/forms

Add a logger service

ng g s services/Logger -m=components/auth/auth.module.ts

create src/app/services/logger.service.spec.ts
create src/app/services/logger.service.ts
update src/app/components/auth/auth.module.ts

Submit and reset

Let's use a Reactive Model Form approach

Reactive forms

  ngOnInit() {
    this.createFormControls();
    this.createForm();

    this.email.valueChanges
      .debounceTime(400)
      .distinctUntilChanged()
      .subscribe(term => {
        this.logger.logInfo(term);
      });
  }
import 'rxjs/add/operator/distinctUntilChanged';
  • subscribe to changes.

Notes:

  • do is used for side-effects.

  • subscribe is used to invoke an observable.

  • Replacing do with subscribe creates undesired results.

  • Replacing subscribe with do will not even invoke the stream.

If we are doing pure functional reactive programming we don't want any side effects in the stream. So, do is discouraged and mostly used only for debugging purposes.

RxJS & Angular

NGRX Store

  • Store - immutable data structure.
  • Actions - describe changes to state.
  • Reducers - pure functions that create a new state.

Install @ngrx/schematics and dependencies

yarn add @ngrx/schematics --dev

yarn add @ngrx/{store,effects,entity,store-devtools}

Generate the initial state management and register it within the app.module.ts

API

ng g st State --root -m app.module.ts -c @ngrx/schematics

create src/app/reducers/index.ts
update src/app/app.module.ts

ng g component components/auth/components/Signup -m components/auth/auth.module.ts --spec

Initial Effects Setup

ng g ef App --root -m app.module.ts -c @ngrx/schematics --group

create src/app/effects/app.effects.ts
create src/app/effects/app.effects.spec.ts
update src/app/app.module.ts
app-routing.module.ts
app.component.html
app.component.scss
app.component.spec.ts
app.component.ts
app.module.ts           <==

components/
effects/                <==
models/
reducers/               <==
services/
shared/

Generate a Feature Set for Auth

Store uses fractal state management, which provides state composition through feature modules, loaded eagerly or lazily.

The createSelector method returns a callback function for selecting a slice of state.

ng generate f components/auth/Auth -m auth.module.ts -g -c @ngrx/schematics

create src/app/components/auth/actions/auth.actions.ts
create src/app/components/auth/reducers/auth.reducer.ts
create src/app/components/auth/reducers/auth.reducer.spec.ts
create src/app/components/auth/effects/auth.effects.ts
create src/app/components/auth/effects/auth.effects.spec.ts
update src/app/components/auth/auth.module.ts

code src/app/components/auth/reducers/index.ts

import { createFeatureSelector } from '@ngrx/store';

import * as auth from './auth.reducer';

export interface AppState {
  authState: auth.State;
}

export const reducers = {
  auth: auth.reducer
};

export const selectAuthState = createFeatureSelector<AppState>('auth');

Add a logger service

ng g s components/auth/services/Auth -m=components/auth/auth.module.ts

NGRX

yarn add ngrx-store-freeze --dev

The example application organizes it like this:

We get the whole State from the Store and select the Substate we want from it via Selectors.

RXJS

Article:

Login

The ofType operator filters the action by a type. It accepts multiple action types, so one effect can handle a number of actions.

Then, with map, we "map" the action to its payload. This, essentially, returns an observable with just the payload.

The switchMap is used to switch back to the response observable but still use the payload as an argument in the switchMap function.

LoginSuccess

The pipe method, which is used to compose a number of functions to act on the observable.

Again, ofType associates the effect with an action while tap performs a side effect transparently. In other words, it returns an observable identical to the source. In our case, we’re adding the token to localStorage and then redirecting the user to /.

Note: It’s a good practice to also dispatch a success or error action based on the result of the request.

Server

cd ~/Sites/angular/ngrx/ngrxApp/server

npm install body-parser cookie-parser cors express

npm start

chrome http://localhost:1337

Add HTTP Interceptor

ng g s components/auth/services/AuthInterceptor -m=components/auth/auth.module.ts

create src/app/components/auth/services/auth-interceptor.service.spec.ts
create src/app/components/auth/services/auth-interceptor.service.ts
update src/app/components/auth/auth.module.ts

Add Auth Guard

navigateByUrl() takes a string as a parameter.

navigate() takes an array of URL segments as a parameter.

ng g guard components/auth/guard/Auth -m=components/auth/auth.module.ts

create src/app/components/auth/guard/auth.guard.spec.ts
create src/app/components/auth/guard/auth.guard.ts
update src/app/components/auth/auth.module.ts
ng g component components/auth/components/Ping -m components/auth/auth.module.ts --spec

create src/app/components/auth/components/ping/ping.component.scss
create src/app/components/auth/components/ping/ping.component.html
create src/app/components/auth/components/ping/ping.component.spec.ts
create src/app/components/auth/components/ping/ping.component.ts
update src/app/components/auth/auth.module.ts