Skip to content

Commit 9b49d6e

Browse files
author
Evan Schultz
committed
fix(select): Chained actions and Injectables
* fix angular-redux#149 - chained actions should not get stale state, changed to create an observable from redux since redux 3.4x supports an observable shim * fix angular-redux#138 - ability to use select decorators in service Changing to use redux's observable, had to change how we created the initial observable. Use switchMap to switch streams once the store observable becomes available
1 parent 3816ca7 commit 9b49d6e

File tree

12 files changed

+424
-25
lines changed

12 files changed

+424
-25
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { NgRedux } from 'ng2-redux';
2+
3+
export const SEARCH_ACTIONS = {
4+
SEARCH: 'SEARCH',
5+
SEARCH_RESULT: 'SEARCH_RESULT',
6+
TERMINATE: 'TERMINATE',
7+
SEARCH_NEXT: 'SEARCH_NEXT',
8+
SEARCH_PREVIOUS: 'SEARCH_PREVIOUS'
9+
};
10+
11+
import { Injectable } from '@angular/core';
12+
@Injectable()
13+
export class SearchActions {
14+
constructor(private ngRedux: NgRedux<any>) {}
15+
16+
searchDispatch(keyword: string) {
17+
this.ngRedux.dispatch(this.search(keyword));
18+
}
19+
20+
fetchResultDispatch(total: number) {
21+
this.ngRedux.dispatch(this.fetchResult(total));
22+
}
23+
24+
private search(keyword: string) {
25+
return {
26+
type: SEARCH_ACTIONS.SEARCH,
27+
payload: keyword
28+
};
29+
}
30+
31+
private fetchResult(total: number) {
32+
return {
33+
type: SEARCH_ACTIONS.SEARCH_RESULT,
34+
payload: {
35+
total: total
36+
}
37+
};
38+
}
39+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { Component, Input } from '@angular/core';
2+
import { Observable } from 'rxjs/Observable';
3+
import { NgRedux } from 'ng2-redux';
4+
import 'rxjs/add/operator/combineLatest';
5+
import { SearchActions } from '../actions/search-actions';
6+
7+
@Component({
8+
selector: 'search-info',
9+
providers: [SearchActions],
10+
template: `
11+
<ul>
12+
<li>{{ search$ | async | json}}</li>
13+
</ul>
14+
`
15+
})
16+
export class SearchInfo {
17+
18+
private search$: Observable<any>;
19+
private test;
20+
21+
constructor(private ngRedux: NgRedux<any>, private actions: SearchActions) { }
22+
23+
ngOnInit() {
24+
this.search$ = this.ngRedux.select(state => state.searchReducer.keyword);
25+
this.search$.subscribe((keyword) => {
26+
if (keyword != '') {
27+
this.actions.fetchResultDispatch(keyword.length)
28+
}
29+
});
30+
}
31+
ngAfterViewInit() {
32+
33+
34+
}
35+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { Component } from '@angular/core';
2+
import { NgRedux, select } from 'ng2-redux';
3+
import { SearchActions } from '../actions/search-actions';
4+
import { Observable } from 'rxjs/Rx';
5+
6+
@Component({
7+
selector: 'search',
8+
providers: [SearchActions],
9+
template: `
10+
<p>
11+
Counter: {{ counter }} <br/>
12+
Counter$ Async: {{ counter$ | async }} <br/>
13+
<input id='search-input' type="text" class="search"
14+
[(ngModel)]="keyword" (ngModelChange)="searchKeyword()"/>
15+
</p>
16+
`
17+
})
18+
export class Search {
19+
counter$: Observable<any>;
20+
search$: Observable<any>;
21+
counter;
22+
keyword: string;
23+
24+
constructor(private actions: SearchActions, private ngRedux: NgRedux<any>) { }
25+
26+
ngOnInit() {
27+
this.counter$ = this.ngRedux.select(state => state.searchReducer.total);
28+
this.search$ = this.ngRedux.select(state => state.searchReducer.keyword);
29+
30+
31+
32+
this.search$.subscribe((keyword) => {
33+
if (keyword != '') {
34+
this.actions.fetchResultDispatch(keyword.length)
35+
}
36+
});
37+
38+
this.counter$.subscribe(state => {
39+
40+
this.counter = state;
41+
});
42+
43+
44+
45+
46+
47+
}
48+
49+
private searchKeyword() {
50+
this.actions.searchDispatch(this.keyword);
51+
}
52+
}

examples/counter/containers/App.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,28 @@ import { NgRedux } from 'ng2-redux';
44

55
import { Counter } from '../components/Counter';
66
import { CounterInfo } from '../components/CounterInfo';
7+
import { Search } from '../components/search.component';
8+
import { SearchInfo } from '../components/search-info.component';
79
import { RootState, enhancers } from '../store';
810

911
import reducer from '../reducers/index';
1012
const createLogger = require('redux-logger');
1113

1214
@Component({
1315
selector: 'root',
14-
directives: [Counter, CounterInfo],
16+
directives: [Counter, CounterInfo, Search, SearchInfo],
1517
pipes: [AsyncPipe],
1618
template: `
19+
20+
<br/>
1721
<counter></counter>
1822
<counter-info></counter-info>
23+
<search-info></search-info>
24+
<search></search>
25+
26+
27+
28+
1929
`
2030
})
2131
export class App {

examples/counter/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { bootstrap } from '@angular/platform-browser-dynamic';
22
import { App } from './containers/App';
33
import { NgRedux } from 'ng2-redux';
4+
import { SearchActions } from './actions/search-actions';
45

5-
bootstrap(App, [ NgRedux ]);
6+
bootstrap(App, [ NgRedux, SearchActions]);

examples/counter/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"scripts": {
77
"postinstall": "typings install",
88
"start": "webpack-dev-server -d --inline --progress --no-info --config webpack.config.js",
9-
"dev": "webpack-dev-server -d --inline --progress --no-info --config webpack.dev.config.js"
9+
"dev": "webpack-dev-server -d --inline --progress --no-info --config webpack.dev.config.js --host 127.0.0.1"
1010
},
1111
"repository": {
1212
"type": "git",

examples/counter/reducers/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ const { combineReducers } = Redux;
33
import { RootState } from '../store';
44
import counter from './counter';
55
import pathDemo from './path-demo';
6-
6+
import searchReducer from './search';
77
const rootReducer = combineReducers<RootState>({
88
counter,
9-
pathDemo
9+
pathDemo,
10+
searchReducer
1011
});
1112

1213
export default rootReducer;

examples/counter/reducers/search.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { SEARCH_ACTIONS } from '../actions/search-actions';
2+
3+
export interface SearchState {
4+
onSearch: boolean;
5+
keyword: string;
6+
total: number;
7+
}
8+
9+
const searchInitState: SearchState = {
10+
onSearch: false,
11+
keyword: '',
12+
total: -1
13+
};
14+
15+
export default function searchReducer(state = searchInitState, action):
16+
SearchState {
17+
switch (action.type) {
18+
case SEARCH_ACTIONS.SEARCH:
19+
return Object.assign({}, state, {
20+
onSearch: true,
21+
keyword: action.payload,
22+
total: state.total
23+
});
24+
case SEARCH_ACTIONS.SEARCH_RESULT:
25+
let total = action.payload.total;
26+
return Object.assign({}, state, {
27+
onSearch: state.onSearch,
28+
keyword: state.keyword,
29+
total
30+
});
31+
default:
32+
return state;
33+
}
34+
}

examples/counter/store/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ if (window.devToolsExtension) {
88
enhancers.push(window.devToolsExtension());
99
}
1010

11+
1112
export interface RootState {
1213
counter: number;
1314
pathDemo: Object;

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
{
22
"name": "ng2-redux",
3-
"version": "3.2.0",
3+
"version": "3.2.1-beta.0",
44
"description": "Angular 2 bindings for Redux",
55
"main": "./lib/index.js",
66
"scripts": {
77
"build": "npm run typings && rimraf ./lib; tsc; rimraf ./lib/___tests___",
8-
"test": "npm run typings && npm run lint && npm run mocha",
8+
"test": "npm run typings && npm run mocha",
99
"typings": "rimraf ./typings && typings install",
1010
"mocha": "ts-node ./node_modules/mocha/bin/_mocha --opts ./src/___tests___/mocha.opts",
1111
"lint": "tslint 'src/**/*.ts' 'examples/counter/**.ts --exclude 'examples/counter/node_modules"
@@ -57,6 +57,7 @@
5757
"rxjs": "5.0.0-beta.6",
5858
"sinon": "^1.16.1",
5959
"sinon-chai": "^2.8.0",
60+
"symbol-observable": "^1.0.1",
6061
"ts-loader": "^0.8.1",
6162
"ts-node": "^0.5.5",
6263
"tslint": "^3.11.0",

0 commit comments

Comments
 (0)