Skip to content

Instantly share code, notes, and snippets.

@esperancaJS
Last active May 25, 2017 00:26
Show Gist options
  • Save esperancaJS/3e914e805d303d9b92df906ce81bb1b0 to your computer and use it in GitHub Desktop.
Save esperancaJS/3e914e805d303d9b92df906ce81bb1b0 to your computer and use it in GitHub Desktop.

1.Install

npm install @ngrx/core @ngrx/store --save

2.Create The State

├─app/
├─state/
│   ├─todo-list/
│   │   ├─todo-list.[actions|reducer|state].ts

todo.list.state.ts

export interface State {
    todos: Array<Todo>;
};

export interface Todo {
    name: string;
    done: boolean;
};

export const intitialState: State = {
    todos: [
        { name: 'clean room', done: false },
        { name: 'make pancakes', done: false },
        { name: 'spend 3 hours on reddit', done: true }
    ]
};

todo.list.actions.ts

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

export const TodoListActionTypes = {
    ADD_TODO: '[TODO-LIST] ADD_TODO',
    TOGGLE_TODO: '[TODO-LIST] TOGGLE_TODO',
};

export const TodoListActions = {
    AddTodoAction: class implements Action {
        readonly type = TodoListActionTypes.ADD_TODO;
        constructor(public payload: {name: string}) { }
    },

    ToggleTodoAction: class implements Action {
        readonly type = TodoListActionTypes.TOGGLE_TODO;
        constructor(public payload: {name: string, done?: boolean}) { }
    },
};

todo.list.reducer.ts

import { ActionReducer, Action } from '@ngrx/store';

import { State, intitialState } from './todo-list.state';
import { TodoListActionTypes } from './todo-list.actions';

export function todoListReducer(state = intitialState, action: Action) {
    switch (action.type) {
        case TodoListActionTypes.ADD_TODO: {
            const newstate = Object.assign({}, state);
            newstate.todos = [
                ...newstate.todos,
                {
                    name: action.payload.name,
                    done: false,
                }
            ];
            return newstate;
        }

        case TodoListActionTypes.TOGGLE_TODO: {
            const newstate = Object.assign({}, state);
            const index = newstate.todos.findIndex(todo => todo.name === action.payload.name);
            newstate.todos[index].done = !newstate.todos[index].done;
            return newstate;
        }

        default: {
            return state;
        }
    }
}

inject it into the app on app.module.ts

(...)
import { StoreModule } from '@ngrx/store';

(...)
import { todoListReducer } from './../state/todo-list/todo-list.reducer';

@NgModule({
    (...)
    imports: [
        (...)
        StoreModule.provideStore({
            todoListStore: todoListReducer
        }),

3. Replace the old logic

On todo-list.component.ts

Add/replace the following:

import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Rx';

import { TodoListActions } from '../../state/todo-list/todo-list.actions';
import { State } from '../../state/todo-list/todo-list.state';

(...)
export class TodoListComponent implements OnInit {

    list$: Observable<boolean>;

    constructor(private store: Store<State>) {
        this.list$ = this.store.select('todoListStore');
    }

    (...)

    addTask(name: string) {
        this.store.dispatch(
            new TodoListActions.AddTodoAction ({ name })
        );
    }

On todo-list.component.html

Replace the *ngfor with

*ngFor="let task of (list$ | async).todos"

On todo-item.component.ts

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

import { TodoListActions } from '../../../state/todo-list/todo-list.actions';
import { State } from '../../../state/todo-list/todo-list.state';

	(...)

    constructor(private store: Store<State>) { }

    (...)

    toggleTodo(name: string) {
        this.store.dispatch(
            new TodoListActions.ToggleTodoAction ({ name })
        );
    }

On todo-item.component.html

Replace [(ngModel)] with [ngModel]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment