我正在使用Angular 5和SignalR构建一个应用程序。我创建了一个服务来管理hub,当服务器发送事件时,它会将值放入BehaviorSubject私有变量中。有一个只读属性应该输出可观察对象,我可以从组件中订阅。
在组件中,我已经订阅了服务的可观察对象,但是当属性更新时它仍然不会更新。
我知道“test”属性正在更新,因为我有警报告诉我我收到了来自服务器的配置。
请问有人能指出我可能遗漏的内容,或者我没有完全理解Angular如何处理更改检测,或者我可能破坏了什么吗?
服务:
在组件中,我已经订阅了服务的可观察对象,但是当属性更新时它仍然不会更新。
我知道“test”属性正在更新,因为我有警报告诉我我收到了来自服务器的配置。
请问有人能指出我可能遗漏的内容,或者我没有完全理解Angular如何处理更改检测,或者我可能破坏了什么吗?
服务:
import { Injectable, Input, Output, EventEmitter, NgZone } from '@angular/core';
import { Http, Response } from '@angular/http';
import 'rxjs/add/operator/map';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import { APIModels } from './../../shared/APIModels';
import {Observable} from "rxjs/Observable";
declare var $;
@Injectable()
export class DisplayViewerConfigurationService {
private _displayConfiguration: BehaviorSubject<APIModels.ClientConfigurationModel>;
public readonly displayConfiguraiton: Observable<APIModels.ClientConfigurationModel>;
public hubProxy;
@Input() displayID;
constructor(public http: Http) {
var test = new APIModels.ClientConfigurationModel();
test.Display = new APIModels.DisplayConfig();
test.Display.DisplayID = "testID";
this._displayConfiguration = new BehaviorSubject(test);
this.displayConfiguraiton = this._displayConfiguration.asObservable();
}
public startConnection(): void {
var hubConnection = $.hubConnection("http://localhost:49890", {useDefaultCredentials: true});
this.hubProxy = hubConnection.createHubProxy('testHub');
hubConnection.qs = "displayid=" + this.displayID;
this.hubProxy.on('receiveConfig', (e: any) => {
this._displayConfiguration.next(e);
alert("now" + JSON.stringify(e));
});
hubConnection.start();
}
}
组件 TS:
import { Component, OnInit, Output, Input, ChangeDetectorRef } from '@angular/core';
import { DisplayViewerConfigurationService } from './../../services/displayviewerconfiguration-service/displayviewerconfiguration-service';
import 'rxjs/symbol/observable';
import { Observable } from 'rxjs/observable';
import { APIModels } from './../../shared/APIModels';
import { Helpers } from './../../shared/Helpers';
@Component({
selector: 'app-displayiframe',
templateUrl: './display-iframe.component.html',
})
export class DisplayScreenComponent implements OnInit {
constructor(public viewer: DisplayViewerConfigurationService) {
this.viewer.displayID = "278307b8-da34-4569-8b93-d5212b9e0e0d";
this.viewer.startConnection();
this.ObjCopy = new Helpers.ObjectCopyHelpers();
}
ngOnInit() {
this.viewer.displayConfiguraiton.subscribe(data => {this.test = data; alert(JSON.stringify(this.test);});
}
@Input() test: any;
public stackHeight: string;
public ObjCopy: Helpers.ObjectCopyHelpers;
}
组件模板:
<div>
{{test.Display.DisplayID}}
</div>
我也尝试过直接订阅这个可观察对象,但仍然没有成功。
<div>
{{viewer.displayConfiguraiton.Display.DisplayID | async}}
</div>
编辑:
包括模块和父组件,以帮助提供进一步的澄清。
模块:
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DisplayViewerConfigurationService } from './../services/displayviewerconfiguration-service/displayviewerconfiguration-service';
import { DisplayViewerComponent } from './display-viewer.component';
import { DisplayScreenComponent } from './display-iframe/display-iframe.component';
import { HttpModule } from '@angular/http';
import { APIModels } from "./../shared/APIModels";
import { Helpers } from "./../shared/Helpers";
@NgModule({
imports: [
CommonModule
HttpModule,
],
declarations: [DisplayViewerComponent, DisplayScreenComponent],
entryComponents: [DisplayViewerComponent, DisplayScreenComponent],
providers: [DisplayViewerConfigurationService],
exports: [DisplayViewerComponent],
})
export class DisplayViewerModule { }
父组件:
import { Component, OnInit } from '@angular/core';
import { NouisliderModule, NouisliderComponent } from 'ng2-nouislider/src/nouislider';
import { DisplayViewerConfigurationService } from './../services/displayviewerconfiguration-service/displayviewerconfiguration-service';
import { DisplayScreenComponent } from './display-iframe/display-iframe.component';
import 'rxjs/symbol/observable';
import { Observable } from 'rxjs/observable';
@Component({
selector: 'app-displayviewer',
templateUrl: './display-viewer.component.html'
})
export class DisplayViewerComponent implements OnInit {
constructor() {
}
ngOnInit() {
}
}
父组件模板:
<app-displayiframe></app-displayiframe>
编辑:
我进行了一些研究,并决定尝试这个示例:使用 Web Sockets 推送实时数据到 Angular 服务。
即使在这样做后,相同的行为仍然存在,没有触发任何变化检测。
经过更多的研究并找到这个页面:Angular 2 - 模型更改后视图不更新。
我决定在更新组件属性后尝试运行 ChangeDetectorRef.detectChanges();
。这样做实际上解决了我的问题,并导致组件按预期更新。
示例:
this.viewer.startConnection()
.subscribe(config => {
this.test.push(config);
alert(JSON.stringify(this.test));
this.changeDetector.detectChanges();
alert(NgZone.isInAngularZone());
});
我还添加了一个提示,告诉我运行的代码是否在AngularZone内。结果显示,我返回的observable似乎不在Angular Zone中。难怪当更改属性时我没有得到任何变化检测。
为什么用这种方式创建observable会导致订阅在AngularZone之外?有没有办法将其修复为在该区域范围内,而不必依赖手动强制应用程序检测更改?