Angular2 Notes III

  • Angular 2 Notes - Modules

  • State Management

  • The Problem With Concurrency

    Building components which communicate with each other is a typical task involving state. We frequently have to keep up to date with different Angular components interacting with the same state: when more than one component accesses and modifies that state we call it shared mutable state.

  • keeping the state consistent

Create a store to manage the state. E.g., the state of Note can be accessed from the store.

import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Injectable } from '@angular/core';
import 'rxjs/Rx';

export interface Note {
color: string,
title: string,
value: string,
id?: string | number,
createdAt?: string,
updatedAt?: string,
userId?: string
}

export interface State {
notes: Array<Note>
}

const defaultState : State = {
notes: []
}

const _store = new BehaviorSubject<State>(defaultState);

@Injectable()
export class Store {
private _store = _store;
changes = this._store.asObservable().distinctUntilChanged()

setState(state: State) {
this._store.next(state);
}

getState(): State {
return this._store.value;
}

purge() {
this._store.next(defaultState);
}
}

Apply a store-helper service to keep state…

import { Injectable } from '@angular/core';
import { Store } from '../store';

@Injectable()
export class StoreHelper {
constructor(private store: Store) {}

update(prop, state) {
const currentState = this.store.getState();
this.store.setState(Object.assign({}, currentState, { [prop]: state }));
}

add(prop, state) {
const currentState = this.store.getState();
const collection = currentState[prop];
this.store.setState(Object.assign({}, currentState, { [prop]: [state, ...collection] }));
}

findAndUpdate(prop, state) {
const currentState = this.store.getState();
const collection = currentState[prop];

this.store.setState(Object.assign({}, currentState, {[prop]: collection.map(item => {
if (item.id !== state.id) {
return item;
}
return Object.assign({}, item, state)
})}))
}

findAndDelete(prop, id) {
const currentState = this.store.getState();
const collection = currentState[prop];
this.store.setState(Object.assign({}, currentState, {[prop]: collection.filter(item => item.id !== id)}));
}
}
```

Apply the store...

```js
export class Notes {
notes = [];

constructor(
private store: Store,
private noteService: NoteService
)
{
this.noteService.getNotes().subscribe();

// this.store.changes.pluck('notes')
// .subscribe((notes: any) => this.notes = notes);

this.store.changes
.map(data => data.notes)
.subscribe(notes => this.notes = notes);
}

onCreateNote(note) {
this.noteService.createNote(note)
.subscribe();
// .subscribe(note => this.notes.push(note));
}

onNoteChecked(note) {
this.noteService.completeNote(note)
.subscribe();
// .subscribe(note => {
// const i = this.notes.findIndex(localNote => localNote.id === note.id);
// this.notes.splice(i, 1);
// });
}
}

  • Authentication Management

Create authentication service, auth.ts

import { Injectable } from '@angular/core';
import {CanActivate, Router} from '@angular/router';
import 'rxjs/Rx';

@Injectable()
export class AuthService implements CanActivate {
JWT_KEY: string = 'retain_token';
JWT: string = '';

constructor(private router: Router) {}

isAuthorized(): boolean {
return Boolean(this.JWT);
}

canActivate(): boolean {
const canActivate = this.isAuthorized();
this.onCanActivate(canActivate);
return canActivate;
}

onCanActivate(canActivate: boolean) {
if (!canActivate) {
this.router.navigate(['', 'auth']);
}
}
}

Add auth control in routes.ts.

import { RouterModule } from '@angular/router';
import { ModuleWithProviders } from '@angular/core';
import { Main, Notes, About, Auth } from './containers';
import { AuthService } from './services';

export const routes: ModuleWithProviders = RouterModule.forRoot([
{
path: '',
component: Main,
canActivate: [ AuthService ],
children: [
{ path: '', component: Notes },
{ path: 'about', component: About }
]
},
{ path: 'auth', component: Auth},
{ path: '**', redirectTo: '' }
]);

Auth page for example…

import { Component } from '@angular/core';
@Component({
selector: 'auth-container',
template: ` <div class="auth-container">
<h1>Auth</h1>
</div>
`
})
export class Auth {}