Skip to content

Commit

Permalink
feat(todo): add todo ngrx demo
Browse files Browse the repository at this point in the history
  • Loading branch information
pengkobe committed Nov 8, 2018
1 parent 07ac08b commit dfbffeb
Show file tree
Hide file tree
Showing 32 changed files with 1,594 additions and 11 deletions.
19 changes: 9 additions & 10 deletions src/app/pages/list/calendar/calendar.page.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,20 @@
Ionic pages and navigation.
-->
<ion-header>

<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
<ion-back-button text="返回" defaultHref="list"></ion-back-button>
</ion-buttons>
<ion-title>Calendar 演示</ion-title>
</ion-toolbar>

</ion-header>


<ion-content padding>
<!-- <ion-calendar [(ngModel)]="date"
(onChange)="onChange($event)"
[type]="type"
[format]="'YYYY-MM-DD'">
</ion-calendar> -->
</ion-content>
<!--
<ion-calendar [(ngModel)]="date"
(onChange)="onChange($event)"
[type]="type"
[format]="'YYYY-MM-DD'">
</ion-calendar>
-->
</ion-content>
2 changes: 1 addition & 1 deletion src/app/pages/list/list.page.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
You navigated here from <b>{{ selectedItem.title }}</b>
</div>

<ion-button (click)="toHome()" color="primary">返回首页</ion-button>
<!-- <ion-button (click)="toHome()" color="primary">返回首页</ion-button> -->



Expand Down
5 changes: 5 additions & 0 deletions src/app/pages/list/list.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ export class ListPage {
note: '',
icon: 'speedometer',
},
{
title: 'todo',
note: '',
icon: 'create',
},
{
title: 'calendar',
note: '',
Expand Down
5 changes: 5 additions & 0 deletions src/app/pages/list/list.router.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ const routes: Routes = [
path: 'echarts',
component: EchartsPage,
},
{
path: 'todo',
// outlet: 'todo',
loadChildren: './ngrxtodo/ngrxtodo.module#NgrxTodoPageModule',
},
];

@NgModule({
Expand Down
33 changes: 33 additions & 0 deletions src/app/pages/list/ngrxtodo/footer/footer.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<footer id="footer" class="footer" *ngIf="showFooter" style="height:100px">
<span id="todo-count" class="todo-count">{{ countTodos }} items left</span>
<ul id="filters" class="filters">
<li>
<a [routerLink]="['./']" [class.selected]="currentFilter == 'SHOW_ALL'">
All
</a>
</li>
<li>
<a
[routerLink]="['./', 'active']"
[class.selected]="currentFilter == 'SHOW_ACTIVE'"
>
Active
</a>
</li>
<li>
<a
[routerLink]="['./', 'completed']"
[class.selected]="currentFilter == 'SHOW_COMPLETED'"
>
Completed
</a>
</li>
</ul>
<button
id="clear-completed"
class="clear-completed"
(click)="clearCompleted()"
>
Clear completed
</button>
</footer>
113 changes: 113 additions & 0 deletions src/app/pages/list/ngrxtodo/footer/footer.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { Component } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { StoreModule, Store } from '@ngrx/store';
import { RouterTestingModule } from '@angular/router/testing';

import { ngrxtodoReducer, AppState } from './../../redux/ngrxtodo.reducer';
import * as FilterActions from './../../redux/filter/filter.actions';
import * as TodoActions from './../../redux/todo/todo.actions';

import { FooterComponent } from './footer.component';

@Component({
// tslint:disable-next-line:component-selector
selector: 'blank-cmp',
template: ``
})
// tslint:disable-next-line:component-class-suffix
export class BlankCmp {
}

describe('FooterComponent', () => {
let component: FooterComponent;
let fixture: ComponentFixture<FooterComponent>;
let store: Store<AppState>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
FooterComponent,
BlankCmp
],
imports: [
RouterTestingModule.withRoutes([
{path: '', component: BlankCmp}
]),
StoreModule.forFeature('ngrxtodo', ngrxtodoReducer),
]
})
.compileComponents();
}));

beforeEach(() => {

store = TestBed.get(Store);
spyOn(store, 'dispatch').and.callThrough();

fixture = TestBed.createComponent(FooterComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should be created', () => {
expect(component).toBeTruthy();
});

describe('Test for clearCompleted', () => {

it('should dispatch an action', () => {
component.clearCompleted();
const action = new TodoActions.ClearCompletedAction();
expect(store.dispatch).toHaveBeenCalledWith(action);
});

});

describe('Test for completedAll', () => {

it('should dispatch an action', () => {
component.completedAll();
const action = new TodoActions.CompletedAllAction();
expect(store.dispatch).toHaveBeenCalledWith(action);
});

});

describe('Test for countTodos', () => {

it('should return 2 undone todos and showFooter is true', () => {
const todos = [
{ id: 1, text: 'todo', completed: false },
{ id: 2, text: 'todo', completed: true },
{ id: 3, text: 'todo', completed: false },
];
const action = new TodoActions.PopulateTodosAction(todos);
store.dispatch(action);
fixture.detectChanges();
expect(component.countTodos).toEqual(2);
expect(component.showFooter).toBeTruthy();
});

it('should return 0 undone todos and showFooter is false', () => {
const todos = [];
const action = new TodoActions.PopulateTodosAction(todos);
store.dispatch(action);
fixture.detectChanges();
expect(component.countTodos).toEqual(0);
expect(component.showFooter).toBeFalsy();
});

});

describe('Test for currentFilter', () => {

it('should currentFilter be "SHOW_ALL"', () => {
const action = new FilterActions.SetFilterAction('SHOW_ALL');
store.dispatch(action);
fixture.detectChanges();
expect(component.currentFilter).toEqual('SHOW_ALL');
});

});
});
54 changes: 54 additions & 0 deletions src/app/pages/list/ngrxtodo/footer/footer.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Component, OnInit } from '@angular/core';
import { Store } from '@ngrx/store';

import { AppState } from './../../redux/ngrxtodo.reducer';
import * as FilterActions from './../../redux/filter/filter.actions';
import * as TodoActions from './../../redux/todo/todo.actions';
import { getStateCompleted, getFilter,getTodos } from './../../redux/todo/todo.selectors';

@Component({
selector: 'app-footer',
templateUrl: './footer.component.html'
})
export class FooterComponent implements OnInit {

countTodos: number;
currentFilter: string;
showFooter: boolean;

constructor(
private store: Store<AppState>
) {
this.readFilterState();
this.readTodosState();
}

ngOnInit() {
}

clearCompleted() {
const action = new TodoActions.ClearCompletedAction();
this.store.dispatch(action);
}

completedAll() {
const action = new TodoActions.CompletedAllAction();
this.store.dispatch(action);
}

private readTodosState() {
this.store.select(getTodos)
.subscribe(todos => {
this.countTodos = todos.filter(t => !t.completed).length;
this.showFooter = todos.length > 0;
});
}

private readFilterState() {
this.store.select(getFilter)
.subscribe(fitler => {
this.currentFilter = fitler;
});
}

}
9 changes: 9 additions & 0 deletions src/app/pages/list/ngrxtodo/new-todo/new-todo.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<input
id="new-todo"
class="new-todo"
type="text"
autofocus
(keyup.enter)="saveTodo()"
placeholder="What needs to be done?"
[formControl]="textField" />

92 changes: 92 additions & 0 deletions src/app/pages/list/ngrxtodo/new-todo/new-todo.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { Component } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
import { StoreModule, Store } from '@ngrx/store';
import { RouterTestingModule } from '@angular/router/testing';

import { ngrxtodoReducer, AppState } from './../../redux/ngrxtodo.reducer';
import * as TodoActions from './../../redux/todo/todo.actions';

import { NewTodoComponent } from './new-todo.component';

@Component({
// tslint:disable-next-line:component-selector
selector: 'blank-cmp',
template: ``
})
// tslint:disable-next-line:component-class-suffix
export class BlankCmp {
}

describe('NewTodoComponent', () => {
let component: NewTodoComponent;
let fixture: ComponentFixture<NewTodoComponent>;
let store: Store<AppState>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
NewTodoComponent,
BlankCmp
],
imports: [
ReactiveFormsModule,
FormsModule,
RouterTestingModule.withRoutes([
{path: '', component: BlankCmp}
]),
StoreModule.forFeature('ngrxtodo', ngrxtodoReducer),
]
})
.compileComponents();
}));

beforeEach(() => {

store = TestBed.get(Store);
spyOn(store, 'dispatch').and.callThrough();

fixture = TestBed.createComponent(NewTodoComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should be created', () => {
expect(component).toBeTruthy();
});

describe('Test for textField', () => {

it('should textField be defined', () => {
expect(component.textField).toBeDefined();
});

it('should textField be valid', () => {
component.textField.setValue('new todo');
expect(component.textField.valid).toBeTruthy();
});

it('should textField be invalid', () => {
component.textField.setValue('');
expect(component.textField.invalid).toBeTruthy();
});

});

describe('Test for saveTodo', () => {

it('should dispatch an action', () => {
component.textField.setValue('new todo', {emitEvent: false});
component.saveTodo();
expect(store.dispatch).toHaveBeenCalled();
});

it('should set value of textField in empty', () => {
component.textField.setValue('new todo', {emitEvent: false});
component.saveTodo();
expect(component.textField.value).toEqual('');
});

});
});
Loading

0 comments on commit dfbffeb

Please sign in to comment.