具有原始值的角按变化检测策略

时间:2018-11-26 07:10:14

标签: angular typescript

可能是我误解了angular的changeDetection策略。

这是说明:

  • 我有2个同级组件(​​S1和S2)
  • 将这两个组件都视为在其上显示一些图形数据的小部件
  • 加载后,我希望最初在两个组件上显示数据。 (为此,我正在使用行为主题)
  • 我要从S1通知S2触发http服务调用。 (我使用行为主题并在S1中单击按钮时调用.next。我正在S2中订阅相同的可观察对象以获取数据)
  • 我的S2组件已向onPush更改检测策略注册。
  • 在进行HTTP服务调用时,我正在使用loading文本,然后在使用ngIf后使用原始变量this.loading=true/false
  • 删除文本。

现在,我的问题是,当App最初加载时,我可以在S2小部件上看到loading...文本,然后填充数据。

但是当我单击S1中的notify sibling按钮时,它确实触发了服务调用,但是在http处理过程中,我看不到loading...文本。

这是S1的代码:

import { Component, OnInit } from '@angular/core';
import { MessagingService } from '../messaging.service';

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.css']
})
export class ParentComponent implements OnInit {

  constructor(private _sendMessage: MessagingService) { }

  ngOnInit() {
  }
  notifyChild() {
    this._sendMessage.notifySibling();
  }
}

这里是S2的代码:

import { Component, OnInit,ChangeDetectionStrategy ,ChangeDetectorRef} from '@angular/core';
import { MessagingService } from '../messaging.service';
import { switchMap, takeUntil, delay } from 'rxjs/operators';
import { of } from 'rxjs';
@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css'],
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent implements OnInit {
  public loading = true;
  public myData: any;
  constructor(private _receiveMessage: MessagingService,private cd: ChangeDetectorRef) { }

  ngOnInit() {
    this._receiveMessage.registerNotification().pipe(
      switchMap(res => {
        this.loading = true;
        /** Simulate http call below  */
        return of([res.data]).pipe(
          delay(5000)
        )
      })
    ).subscribe(response => {
      this.myData = response;
      this.loading = false;
      this.cd.markForCheck();
    })
  }

}

注意:我已经在订阅中添加了this.cd.markForCheck();。如果我这样评论,我只会看到loading...并且没有数据显示

消息服务:

import { Injectable } from '@angular/core';
import { Subject, BehaviorSubject } from 'rxjs';
@Injectable({
  providedIn: 'root'
})
export class MessagingService {
  public _notify = new BehaviorSubject({ data: "initial Call" });
  public notify = this._notify.asObservable();
  constructor() { }

  notifySibling() {
    this._notify.next({ data: 'call from sibling' });
  }
  registerNotification() {
    return this.notify;
  }

}

完整的示例已发布在stackblitz

1 个答案:

答案 0 :(得分:5)

OnPush策略运行检查仅在更改@Input属性时才能显示,如果要在异步上下文中运行它,则必须在请求之前和请求之后自行调用this.cd.markForCheck()

ngOnInit() {
    this._receiveMessage.registerNotification().pipe(
      switchMap(res => {
        this.loading = true;
        /** note this */
        this.cd.markForCheck();
        return of([res.data]).pipe(
          delay(1000)
        )
      })
    ).subscribe(response => {
      this.myData = response;
      this.loading = false;
      this.cd.markForCheck();
    })
  }

https://stackblitz.com/edit/angular-pmvmgz

英语不是我的母语:(