当Observable返回时,Angular 5组件不会更新

时间:2018-01-30 00:43:10

标签: angular typescript signalr observable angular5

我正在使用Angular 5和SignalR构建应用程序。我创建了一个管理集线器的服务,当事件从服务器进入时,它将值放在BehaviorSubject私有变量中。有一个只读属性应该放出我可以从组件订阅的observable。

在组件中,我订阅了服务的Observable,但在属性更新时仍然没有更新。

我知道“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>

我也试过用这个直接订阅observable。仍然没有奏效。

<div>
   {{viewer.displayConfiguraiton.Display.DisplayID | async}}
</div>

编辑:

包括此堆栈的模块和父组件,以帮助提供进一步的说明。

MODULE:

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>

编辑:

我一直在做一些研究,并决定尝试这个例子:https://blog.codewithdan.com/2017/11/07/pushing-real-time-data-to-an-angular-service-using-web-sockets/

执行此操作后仍保持相同的行为,未触发任何更改检测。

经过一番研究并找到这个页面。 Angular 2 - View not updating after model changes

我决定尝试运行ChangeDetectorRef.detectChanges();在我更新组件的属性后。这样做实际上修复了我的问题并导致组件按照我的预期更新。

示例:

this.viewer.startConnection().subscribe(config => {this.test.push(config); alert(JSON.stringify(this.test)); this.changeDetector.detectChanges();  alert(NgZone.isInAngularZone());});

我还添加了一个警告,告诉我我运行的代码是否在AngularZone中。事实证明,我回来的可观察物似乎不在角度区内。难怪我在更改房产时没有得到任何变更检测。

为什么以这种方式创建observable导致订阅在AngularZone之外?有没有办法可以解决这个问题,使其处于区域范围内,而不必依靠手动强制应用程序检测更改?

~~解

所以,事实证明我正在使用一个不在NgZone中的库。我能够通过使用NgZone.isInAngularZone()来确定调用是否在区域内;并在订阅回调中放置警报。一旦我发现我不在该区域,我发现我可以将ChangeDetectorRef注入组件并在订阅中放置一个手动更改检测调用。示例:this.changeDetector.detectChanges();

这只是根本问题的创可贴。经过一番研究后,我发现了Post。这指出您可以强制在区域内运行呼叫。所以我用这个替换了集线器代理回调。

this.hubProxy.on('receiveConfig', (e: any) => {
            this.ngZone.run(() => this.observer.next(e));
        });

这迫使observable在NgZone中运行,允许默认的更改检测树检测更改。

2 个答案:

答案 0 :(得分:3)

所以,事实证明我正在使用一个不在NgZone中的库。我能够通过使用NgZone.isInAngularZone()来确定调用是否在区域内;并在订阅回调中放置警报。一旦我发现我不在该区域,我发现我可以将ChangeDetectorRef注入组件并在订阅中放置一个手动更改检测调用。示例:this.changeDetector.detectChanges();

这只是根本问题的创可贴。经过一番研究,我发现了这篇帖子。这指出您可以强制在区域内运行呼叫。所以我用这个替换了集线器代理回调。

this.hubProxy.on('receiveConfig', (e: any) => {
            this.ngZone.run(() => this.observer.next(e));
        });

这迫使observable在NgZone中运行,允许默认的更改检测树检测更改。

答案 1 :(得分:0)

想增加我的新手经验...

obs.subscribe(
        (data) => {
            console.log('this was sent to the DB : ' + data);
            this.myItem = data;
            this.itemOUT.emit(this.myItem);
            this.itemCLOSE.emit(true);

        });

我在我的订阅之外有2条发表声明。 发射正在执行,更新之前我正在刷新父组件。

这个时间对我来说有点直觉,但确实发生了(始终如一)。只是为了证明使用异步操作,您无需做任何假设。

事后看来很明显,但是花了很多console.log()-才使​​我意识到自己的错误。

希望它可以帮助某人。