-
https://github.com/ngrx/platform/tree/master/example-app/app
-
https://github.com/angular/angular/tree/master/aio/content/examples
mkdir -p ~/Sites/angular/ngrx && cd ~/Sites/angular/ngrx
npm install -g @angular/cli
ng new ngrxApp --routing --style scss
cd ngrxApp
ng set --global packageManager=yarn
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
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
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
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
|____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
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
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
Now we have routes configured and a place to render them, but how do we navigate?
-
https://github.com/angular/angular-cli/wiki/generate-class
-
https://github.com/ngrx/platform/blob/master/example-app/app/books/models/book.ts
ng g class models/user
Reactive forms:
yarn add @angular/forms
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
ngOnInit() {
this.createFormControls();
this.createForm();
this.email.valueChanges
.debounceTime(400)
.distinctUntilChanged()
.subscribe(term => {
this.logger.logInfo(term);
});
}
-
valueChages
returns an observable that emits the latest values. We can therefore subscribe tovalueChanges
to update instance variables or perform operations. -
distinctUntilChanged
emits when the current value is different than the last: https://www.learnrxjs.io/operators/filtering/distinctuntilchanged.html
import 'rxjs/add/operator/distinctUntilChanged';
subscribe
to changes.
Notes:
-
do
is used for side-effects. -
subscribe
is used to invoke an observable. -
Replacing
do
withsubscribe
creates undesired results. -
Replacing
subscribe
withdo
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.
- Store - immutable data structure.
- Actions - describe changes to state.
- Reducers - pure functions that create a new state.
yarn add @ngrx/schematics --dev
yarn add @ngrx/{store,effects,entity,store-devtools}
-
https://github.com/ngrx/platform/tree/master/docs/schematics#initial-state-setup
-
https://github.com/ngrx/platform/blob/master/docs/schematics/store.md
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
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/
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');
ng g s components/auth/services/Auth -m=components/auth/auth.module.ts
yarn add ngrx-store-freeze --dev
The example application organizes it like this:
-
Main reducer file, which declares the state visible for all modules.
https://github.com/ngrx/platform/blob/master/example-app/app/reducers/index.ts
-
For each feature, a reducer file, which extends from that state and adds its part.
https://github.com/ngrx/platform/blob/master/example-app/app/auth/reducers/index.ts
("export interface State extends fromRoot.State")
-
The components of that feature use that interface and the given selectors.
We get the whole State from the Store and select the Substate we want from it via Selectors.
-
code ./src/app/components/auth/effects/auth.effects.ts
-
https://github.com/ReactiveX/rxjs/blob/master/doc/operators.md
-
https://github.com/ReactiveX/rxjs/blob/master/doc/observable.md
-
https://github.com/ReactiveX/rxjs/blob/master/doc/subject.md#behaviorsubject
-
https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md
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.
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.
cd ~/Sites/angular/ngrx/ngrxApp/server
npm install body-parser cookie-parser cors express
npm start
chrome http://localhost:1337
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
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