如何在angular2中使用changeDetection:ChangeDetectionStrategy.OnPush

时间:2016-07-22 08:40:20

标签: angular

我有简单的angular2应用程序。该应用程序只有一个包含ChangeDetectionStrategy.OnPush的组件。 问题是组件永远不会刷新其视图。 数据阵列更新后如何使组件自行刷新? 这里的代码。我使用的是Angular 2.0.0-rc.4。

的index.html

<head>
<title>Angular 2 QuickStart</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">

<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<!-- 2. Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>
  System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<app style="width:100%;height:100%;">Loading...</app>
</body>

main.ts

import { bootstrap }    from "@angular/platform-browser-dynamic";
import { AppComponent } from "./app";
bootstrap(AppComponent);

app.ts

import {Component, ComponentRef, ComponentFactory, ViewContainerRef} from "@angular/core";
import {ListComponent} from "./list";

@Component({
    selector: "app",
    template: `
    <div>
      <h1>Angular2 - app</h1>
      <gm-list></gm-list>
    </div>
    `,
    directives: [ListComponent]
})
export class AppComponent {
}

list.ts

import {Component, Input, NgZone, ChangeDetectionStrategy, ChangeDetectorRef} from "@angular/core";

@Component({
    selector: "gm-list",
    template: `<div style='width:100%;height:100%;'>
    List
    <div *ngFor="let item of data" >
        <div>
            {{ test }}
        </div>
        <div>
            <label class="checkbox">
                <input type="checkbox" [(ngModel)]="item.visible"> {{ item.name }}
            </label>
        </div>
        </div>
    </div>`,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class ListComponent {
    private _data: any = [];

    constructor(private zone: NgZone, private changeDetectorRef: ChangeDetectorRef) {
    }

    ngOnInit(): void {
        var me = this;
        setTimeout(function () {
            me.data = [
                { id: 1, name: "one", visible: true },
                { id: 2, name: "two", visible: false },
                { id: 3, name: "three", visible: true },
                { id: 4, name: "four", visible: false },
                { id: 5, name: "five", visible: true },
                { id: 6, name: "six", visible: true }
            ];
        }, 3000);
    }

    @Input() set data(data: any) {
        this._data = data;
        console.log("databind");
    }

    get data(): any {
        return this._data;
    }

    get test(): string {
        //console.log("test");
        return "test";
    }
}

2 个答案:

答案 0 :(得分:2)

来自https://github.com/angular/angular/issues/4746#issuecomment-150754049

  

OnPush仅在输入属性具有时才会触发更改检测   由于更改检测检查而被更改

1)因此,您需要通过changeDetectorRef.markForCheck手动运行更改,例如:

export class ListComponent {
    constructor(private changeDetectorRef: ChangeDetectorRef) {}

    ngOnInit(): void {
        setTimeout(() => {
            this.data = [...];
            this.changeDetectorRef.markForCheck();
        }, 3000);
    }
    ...

<强> demo plunker

2)如果你更改了父母的输入数据,它将被更新,因为这将触发对孩子的检查( plunker ):

@Component({
  selector: 'my-app',
  template: `<gm-list [data]="data"></gm-list>`,
  directives: [ListComponent]
})
export class App {
  data:any[];
  constructor() {
     setTimeout(() => {
        this.data = [...];
    }, 3000);
  }
}

3)或者您可以通过使用对父组件的引用(或使用EventEmitter)来运行更新,如下所示:

export class ListComponent {
    constructor(@Inject(forwardRef(() => App)) private parent:App) {}

    ngOnInit(): void {
      setTimeout(() => {
          this.parent.data = [...];
      }, 3000);
    }
}  

@Component({
  selector: 'my-app',
  template: `<gm-list [data]="data"></gm-list>`,
  directives: [ListComponent]
})
export class App {
  data: any[];
}

<强> plunker

答案 1 :(得分:0)

Angular2尚未稳定。代码可能会在发布中更改。找到了以下解决方案,版本为rc4。

1)添加

changeDetection: ChangeDetectionStrategy.OnPush,

2)组件状态改变后调用

this.changeDetectorRef.markForCheck();
this.changeDetectorRef.detectChanges();