2016-03-27 62 views
2

我有一个指令app.service.ts存储应用程序状态数据,以及我试图使用从其他组件这个指令,所以我可以获取和设置应​​用程序的状态(这是工作)。angular2属性更改错误

但是它给了我这个错误,当我尝试从本指令的属性绑定到视图

EXCEPTION: Expression 'loading: {{loadState}} in [email protected]:23' has changed after it was checked. Previous value: 'false'. Current value: 'true' in [loading: {{loadState}} in [email protected]:23]

这里我想显示加载文本,当appState.get().loadState == true

应用.service.ts - source

import {Injectable} from 'angular2/core'; 
import {WebpackState} from 'angular2-hmr'; 

@Injectable() 
export class AppState { 
    _state = {}; // you must set the initial value 
    constructor(webpackState: WebpackState) { 
    this._state = webpackState.select('AppState',() => this._state); 
    } 

    get(prop?: any) { 
    return this._state[prop] || this._state; 
    } 

    set(prop: string, value: any) { 
    return this._state[prop] = value; 
    } 
} 

app.ts

import {AppState} from './app.service'; 

export class App{ 

    constructor(public appState: AppState) { 
     this.appState.set('loadState', false); 
    } 
    get loadState() { 
     return this.appState.get().loadState; 
    } 
} 

app.html

<div class="app-inner"> 
    <p>loading: {{loadState}}</p> 
    <header></header> 
    <main layout="column" layout-fill> 
    <router-outlet></router-outlet> 
    </main> 
</div> 

app.ts假设有一个子组件home.ts并加载到视图

home.ts

export class HomeCmp { 
page; 

constructor(private wp: WPModels, private appState: AppState) {} 

ngOnInit() { 
    var pageId = this.appState.get().config.home_id; 
    this.appState.set('loadState', true); // before http request 

    this.wp.fetch(WPEnpoint.Pages, pageId).subscribe(
    res => { 
     this.page = res; 
     this.appState.set('loadState', false); // after http request 
    }, 
    err => console.log(err) 
    ); 
} 
} 
+0

,可以使用共享对象此。我认为HTML中的{{loadState}}总是会以这种方式抛出错误。而是尝试绑定在服务中使用的一些共享变量。例如。 _state = {}是一个共享对象。设置一些属性,然后在HTML中,你可以通过{{appState._state.someProperty}}来访问它' – micronyks

+0

@micronyks相同的错误 –

回答

1

该解决方案是相当简单的,通过使一个特殊的部件,以从状态显示装载状态服务app.service.ts,这里是代码:

LoaderCmp显示loadState从直接APPSTATE服务属性。

import {Component} from 'angular2/core'; 
import {AppState} from "../../app.service"; 

@Component({ 
    selector: 'loader', 
    template: ` 
    loading state : {{appState._state.loadState}} 
    ` 
}) 

export class LoaderCmp{ 
    constructor(private appState: AppState) {} 
} 

app.service.ts持有我们的应用程序的状态。

import {Injectable} from 'angular2/core'; 
import {WebpackState} from 'angular2-hmr'; 

@Injectable() 
export class AppState { 
    _state = {}; // you must set the initial value 
    constructor(webpackState: WebpackState) { 
    this._state = webpackState.select('AppState',() => this._state); 
    } 

    get(prop?: any) { 
    return this._state[prop] || this._state; 
    } 

    set(prop: string, value: any) { 
    return this._state[prop] = value; 
    } 
} 

app.ts不需要任何配置,只需添加LoaderCmp到应用程序的指令。

@Component({ 
    selector: 'app', 
    directives: [HeaderCmp, LoaderCmp], 
    template: ` 
    <div class="app-inner"> 
    <loader></loader> 
    <header></header> 
    <main> 
     <router-outlet></router-outlet> 
    </main> 
    </div> 
    ` 
}) 
export class App { 
    constructor() { } 
} 

更新应用程序状态从任何组件,例如:home.ts

export class HomeCmp { 
page; 

constructor(private wp: WPModels, private appState: AppState) {} 

ngOnInit() { 
    var pageId = this.appState.get().config.home_id; 
    this.appState.set('loadState', true); // before http request 

    this.wp.fetch(WPEnpoint.Pages, pageId).subscribe(
    res => { 
     this.page = res; 
     this.appState.set('loadState', false); // after http request 
    }, 
    err => console.log(err) 
    ); 
} 
} 
0

我认为你可以充分利用ChangeDetectorRef类及其方法detectChanges。

对于此注入到你的应用程序组件并调用该方法在其ngAfterViewInit。

constructor(private cdr: ChangeDetectorRef) {} 

    ngAfterViewInit() { 
     this.cdr.detectChanges(); 
    } 

详情请参阅此问题:

话虽这么说,我会用一个观察特性到您的状态服务通知组件时,它的读取。

@Injectable() 
export class AppStateService { 
    state: string; 
    state$: Observable<string>; 
    private stateObserver : Observer<string>; 

    constructor(){ 
    this.state$ = new Observable(observer => this.stateObserver = observer).share(); 
    } 

    updateState(newState) { 
    this.state = newState; 
    this.stateObserver.next(newState); 
    } 
} 

而在组件:

@Component({...}) 
export class SomeComponent { 
    constructor(service: AppStateService) { 
    service.state$.subscribe(newState => { 
     (...) 
    }); 
    } 
} 

请参见以下链接了解详情:

+0

我试过这个,但它给了我完全相同的错误 –

+0

你的意思是你试图调用' detectChanges'?在哪个组件生命周期中挂钩?否则,我在我的片段中输入了一个错字。它是'ngAfterViewInit'代替... –

+0

似乎没有必要使用'detectChanges',我喜欢使用observable作为状态服务的想法。但我选择了普通的'app.service.ts',因为它支持多个属性。我为这两种方式写了解决方案。 –

0

wp莫名其妙似乎运行在安格拉斯区以外的代码。要强制代码回Angulars区,使用zone.run()作为代码更新性质如下所示,视图结合:

import {NgZone} from 'angular2/core'; 

export class HomeCmp { 
page; 

constructor(private zone:NgZone, private wp: WPModels, private appState: AppState) {} 

ngOnInit() { 
    var pageId = this.appState.get().config.home_id; 
    this.appState.set('loadState', true); // before http request 

    this.wp.fetch(WPEnpoint.Pages, pageId).subscribe(
    res => { 
     this.zone.run(() => { 
     this.page = res; 
     this.appState.set('loadState', false); // after http request 
     }); 
    }, 
    err => console.log(err) 
    ); 
} 
} 
0

通过使用可观察的和共享功能另一种解决方案,在这里我们用app.state.ts仅支持一个属性改变了app.service.ts

LoaderCmp直接显示来自appState服务的loadState属性。

import {Component} from 'angular2/core'; 
import {AppStateService} from "../../app.state"; 

@Component({ 
    selector: 'loader', 
    template: ` 
    loading state : {{ active }} 
    ` 
}) 

export class LoaderCmp{ 
    active; 
    constructor(private service: AppStateService) {} 
    ngOnInit() { 
     this.service.state$.subscribe(newState => { 
     this.active = newState; 
    }); 
    } 
} 

app.state.ts持有我们的负载状态。

import "rxjs/add/operator/share"; 
import {Observable} from "rxjs/Observable"; 
import {Observer} from "rxjs/Observer"; 
import {Injectable} from "angular2/core"; 

@Injectable() 
export class AppStateService { 
    state: boolean = false; 
    state$: Observable<boolean>; 
    private stateObserver : Observer<boolean>; 

    constructor(){ 
    this.state$ = new Observable(observer => this.stateObserver = observer).share(); 
    } 

    updateState(newState) { 
     this.state = newState; 
     this.stateObserver.next(newState); 
    } 
} 

app.ts不需要任何配置,只需添加LoaderCmp到应用程序的指令。从任何组件,例如

@Component({ 
    selector: 'app', 
    directives: [HeaderCmp, LoaderCmp], 
    template: ` 
    <div class="app-inner"> 
    <loader></loader> 
    <header></header> 
    <main> 
     <router-outlet></router-outlet> 
    </main> 
    </div> 
    ` 
}) 
export class App { 
    constructor() { } 
} 

更新应用程序状态:home.ts

export class HomeCmp { 
page; 

constructor(private wp: WPModels, private service: AppStateService) {} 

ngOnInit() { 
    this.service.updateState(true); // before http request 

    this.wp.fetch(WPEnpoint.Pages, pageId).subscribe(
    res => { 
     this.page = res; 
     this.service.updateState(false); // after http request 
    }, 
    err => console.log(err) 
    ); 
} 
}