我做了一个应用程序的角-cli,不变和Redux。我遵循了这文章的说明,这篇文章没有描述如何获取数据。我的应用程序需要用异步http调用的数据初始化Redux存储。
我有一个组件来列出具有模板的数据。该组件从存储区获取数据,该存储依赖于进行http调用的服务。http调用可以工作,但是应用程序会抛出一个异常,表明列表组件正在尝试在数据到达之前获取数据。
我的存储库是这里
该应用程序的演示是这里。
错误消息:
main.js:21 TypeError: Cannot read property 'getState' of undefined
at a.get [as objections] (https://dancancro.github.io/bernierebuttals/main.js:18:22268)
at a._View_a0.detectChangesInternal (a.template.js:189:37)
at a.detectChanges (https://dancancro.github.io/bernierebuttals/main.js:32:13138)
at a.detectViewChildrenChanges (https://dancancro.github.io/bernierebuttals/main.js:32:13774)
at a._View_a_Host0.detectChangesInternal (a.template.js:34:8)
at a.detectChanges (https://dancancro.github.io/bernierebuttals/main.js:32:13138)
at a.detectContentChildrenChanges (https://dancancro.github.io/bernierebuttals/main.js:32:13588)
at a.detectChangesInternal (https://dancancro.github.io/bernierebuttals/main.js:32:13345)
at a.detectChanges (https://dancancro.github.io/bernierebuttals/main.js:32:13138)
at a.detectViewChildrenChanges (https://dancancro.github.io/bernierebuttals/main.js:32:13774)下面是代码的一些相关部分:(我正在研究这个问题。存储库包含当前代码)
list.component.html
...
<ul id="objection-list" [sortablejs]="store.objections" [sortablejsOptions]="options" (update)="setTouched()">
<li *ngFor="let objection of store.objections">
<list-objection
[objection]="objection"
[editable]="editable"
(onEdit)="setTouched()"
(onReordered)="setReordered(objection)"
></list-objection>
</li>
</ul>
...list.component.ts
import { Component, OnInit, ContentChildren, QueryList } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { SortablejsOptions, SORTABLEJS_DIRECTIVES } from 'angular-sortablejs';
import Immutable = require('immutable');
import { ObjectionComponent } from './objection/objection.component';
import { ObjectionModel } from '../objection';
import { ObjectionStore } from '../objection-store';
import { DataService } from '../data.service';
import { addObjection } from '../actions';
@Component({
moduleId: module.id,
selector: 'app-list',
templateUrl: 'list.component.html',
styleUrls: ['list.component.css'],
providers: [ObjectionStore, DataService],
directives: [ObjectionComponent, SORTABLEJS_DIRECTIVES]
})
export class ListComponent implements OnInit {
private sub: any;
editable: boolean = false;
touched: boolean = false;
expanded: boolean = false;
options: SortablejsOptions = {
disabled: false
};
objectionID: number;
constructor(
private store: ObjectionStore,
private route: ActivatedRoute) {}
...
}objection-store.ts
import { Injectable } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import Immutable = require('immutable');
import { createStore } from 'redux';
import { ObjectionAction } from './actions';
import { reducer } from './reducer';
import { ObjectionModel } from './objection';
import { DataService } from './data.service';
@Injectable()
export class ObjectionStore {
private sub: any;
store: any;
constructor(
private dataService: DataService) {
this.store = createStore(reducer, Immutable.List<ObjectionModel>(objections.json()));
});
}data.service.ts
import { Injectable } from '@angular/core';
import { Http, Response, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';
import { ObjectionModel } from './objection';
import { Area } from './area';
let objectionsPromise;
@Injectable()
export class DataService {
result: Object;
combined: any;
error: Object;
getUrl: string = 'https://script.google.com/macros/s/AKfycbymzGKzgGkVo4kepy9zKIyDlxbnLbp-ivCvj8mVMClmWgr-V-g/exec?json=1';
postUrl: string = 'https://script.google.com/macros/s/AKfycbymzGKzgGkVo4kepy9zKIyDlxbnLbp-ivCvj8mVMClmWgr-V-g/exec';
static getObjection(objections: any[], id: number): ObjectionModel {
return objections.filter(function(objection) {
return objection.id === id
})[0];
}
constructor(private http: Http) {
objectionsPromise = this.http.get(this.getUrl).toPromise();
}发布于 2016-07-29 00:52:40
基本答案
要回答眼前的问题,从服务器获得反对意见并将其放入模板可以简单地这样做:
<ul id="objection-list"
[sortablejs]="store.objections"
[sortablejsOptions]="options"
(update)="setTouched()">
<li *ngFor="let objection of objections | async">
<list-objection
[objection]="objection"
[editable]="editable"
(onEdit)="setTouched()"
(onReordered)="setReordered(objection)">
</list-objection>
</li>
</ul>@Component({
moduleId: module.id,
selector: 'app-list',
templateUrl: 'list.component.html',
styleUrls: ['list.component.css'],
providers: [ObjectionStore, DataService],
directives: [ObjectionComponent, SORTABLEJS_DIRECTIVES]
})
export class ListComponent implements OnInit {
// ...
private objections: Observable<ObjectionModel[]>;
constructor(
private dataService: DataService,
private route: ActivatedRoute) {}
ngOnInit() {
this.objections = this.dataService.getObjections();
}
// ...import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import { ObjectionModel } from './objection';
@Injectable()
export class DataService {
result: Object;
combined: any;
error: Object;
getUrl: string = 'https://script.google.com/macros/s/AKfycbymzGKzgGkVo4kepy9zKIyDlxbnLbp-ivCvj8mVMClmWgr-V-g/exec?json=1';
postUrl: string = 'https://script.google.com/macros/s/AKfycbymzGKzgGkVo4kepy9zKIyDlxbnLbp-ivCvj8mVMClmWgr-V-g/exec';
getObjections(private http: Http): Observable<ObjectionModel[]> {
return this.http.get(this.getUrl) // returns an observable of the response
.map(response => response.json()); // transforms it into an observable of ObjectionModels
}
}关于Redux的说明
注意,这一切都是在没有Redux的情况下完成的。
总的来说,我喜欢Redux,我经常使用它。然而,在您的示例中,您似乎正在做一些非常规的事情:
如果您使用ng2-redux,情况会更像这样:
顶级应用程序组件:构建您的商店并初始化它:
import { NgRedux } from 'ng2-redux';
import { rootReducer } from './reducers';
@Component({ /* ... */ })
class App {
constructor(private ngRedux: NgRedux<any>) {
this.ngRedux.configureStore(rootReducer, {});
}
}列表组件:将模板绑定到存储区当前数据的选择器。还会在初始化时触发数据获取。
import { NgRedux, select } from 'ng2-redux';
@Component({
moduleId: module.id,
selector: 'app-list',
templateUrl: 'list.component.html',
styleUrls: ['list.component.css'],
providers: [DataService],
directives: [ObjectionComponent, SORTABLEJS_DIRECTIVES]
})
export class ListComponent implements OnInit {
// ...
// Magic selector from ng2-redux that makes an observable out
// of the 'objections' property of your store.
@select('objections') objections: Observable<ObjectionModel[]>;
constructor(
private ngRedux: NgRedux<any>,
private dataService: DataService) {}
ngOnInit() {
this.subscription = this.dataService.getObjections()
.subscribe(objections => this.ngRedux.dispatch({
type: FETCH_OBJECTIONS_OK,
payload: objections
},
error => this.ngRedux.dispatch({
type: FETCH_OBJECTIONS_ERROR,
error: error
});
)
}
}好的..。那么这些数据是如何进入商店的呢?通过减速机。记住,在redux存储状态下,只能从减速机更改。
export function objectionReducer(state = [], action) {
switch(action.type) {
case FETCH_OBJECTIONS_OK: return [ ...action.payload ];
case ADD_OBJECTION: return [ ...state, action.payload ];
// etc.
}
return state;
}我们也可以跟踪一个减速器的错误,如果我们想,你想要如何结构,这取决于你。
export function errorReducer(state = {}, action) {
switch(action.type) {
case FETCH_OBJECTIONS_ERROR: return { objectionFetch: action.error }
}
}由于我们只有一家商店,所以我们将减速机模块化,并将它们组合在一起:
import { combineReducers } from 'redux';
import { objectionReducer } from './objection.reducer';
import { errorReducer } from './error.reducer';
export const rootReducer = combineReducers({
objections: objectionReducer,
error: errorReducer
});更多地学习/披露
信息披露:我是Ng2-Redux的作者之一。然而,Ngrx/Store也是使用Ng2进行redux的一个很好的选择,虽然实现不同,但使用它与我前面描述的非常相似。
我和我的同事还保留了一些关于Angular2和Redux的培训资源,我将在下面提供这些资源:
发布于 2016-07-22 18:31:00
你的数据服务是错误的。你漏掉了诺言的要点[可观察的]。您应该阅读有关http客户端的角度文档。至少读一下这部分:https://angular.io/docs/ts/latest/guide/server-communication.html#!#promises
构造函数中没有http调用!这更像是:
getHeroes (): Promise<Hero[]> {
return this.http.get(this.heroesUrl)
.toPromise()
.catch(this.handleError);
}在你习惯了这一点之后,我真的建议你读一些关于可观察性的文章。更干净更先进。
https://stackoverflow.com/questions/38530860
复制相似问题