简体   繁体   English

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

[英]Angular onpush change detection strategy with primitive values

may be I am misunderstanding the changeDetection strategy in angular. 可能是我误会了angular的changeDetection策略。

Here is Description: 这是说明:

  • I have 2 Sibling components (S1 and S2) 我有2个同级组件(​​S1和S2)
  • Think both the components as widget on which some graphical data being displayed 将这两个组件都视为在其上显示一些图形数据的小部件
  • When loaded I want to display data on both the component initially. 加载后,我想最初在两个组件上显示数据。 (For this I am using behaviour subject) (为此,我正在使用行为主题)
  • From S1 I want to notify S2 to trigger a http service call. 我想从S1通知S2触发http服务调用。 (I have used behaviour subject and calling .next on click of a button in S1. I am subscribing to same observable in S2 to get the data) (我使用行为主题并在S1中单击按钮时调用.next。我正在S2中订阅相同的可观察对象以获取数据)
  • My S2 component is registered with onPush change detection strategy. 我的S2组件已向onPush更改检测策略注册。
  • I am using loading text while http service call is in progress and then removing the text after complete using ngIf using primitive variable this.loading=true/false 我正在使用HTTP服务进行过程中loading文本,然后在使用ngIf完成后删除文本ngIf使用原始变量this.loading=true/false

Now My problem is when App loads initially I can see loading... text on S2 widget and then data gets populated. 现在我的问题是,当App最初loading...时,我可以看到正在S2小部件上loading...文本,然后填充数据。

But when I click on the notify sibling button in S1, it does triggers the service call but while http is in process I can't see loading... text. 但是,当我单击S1中的“ notify sibling按钮时,它确实触发了服务调用,但是在http处理过程中,我看不到正在loading...文本。

Here is code of S1 : 这是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();
  }
}

Here code of S2 : 这是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();
    })
  }

}

Note: I have added this.cd.markForCheck(); 注意:我添加了this.cd.markForCheck(); in subscription. 在订阅中。 If i comment this like I am only seeing loading... and no data being displayed 如果我像这样评论我只看到loading...而没有数据显示

Messaging Service : 讯息服务:

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;
  }

}

Full working example is published on stackblitz 完整的工作示例已发布在stackblitz上

OnPush strategy run check only when @Input property is changed if you want to run it in async context you have to call this.cd.markForCheck() yourself before request and after request. 仅当更改@Input属性时, OnPush策略运行检查,如果要在异步上下文中运行它,则必须在请求之前和之后this.cd.markForCheck()调用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 https://stackblitz.com/edit/angular-pmvmgz

english ain't my native language :( 英语不是我的母语:(

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM