在Worker.onmessage不能按预期工作后,angular2更改检测

时间:2017-01-20 07:30:58

标签: javascript angular angular2-changedetection

我在angular2应用程序中遇到了一个非常有趣的东西,我简化了这里的情况。

这是AppComponnet

export class AppComponent {

    tabs: any = [];

    viewModes = [
       { label: "列表查看"},
       { label: "树状图" },
    ];


   constructor(private changeRef: ChangeDetectorRef) {}

   addTab() {
      var worker = new Worker("worker.js");
      worker.postMessage("");
      worker.onmessage = (event) => {
      this.tabs.push({
         label: 'label'
      })
     this.changeRef.detectChanges();
    }
  }

  currentMode: any;
  selectViewMode(mode: any) {
      if (this.currentMode) {
         this.currentMode.selected = false;
      }
      mode.selected = true;
      this.currentMode = mode;
   }

 }

这是模板

    <div *ngFor="let tab of tabs">
        <ul>
           <li *ngFor="let item of viewModes">
                <a (click)="selectViewMode(item)"     [style.background]="item.selected ? '#f69c55' : ''"> {{item.label}} </a>
           </li>
        </ul>
     </div>

     <button (click)="addTab()">Add Tab</button>

当工作人员完成时,我将新选项卡推送到选项卡。并且angular2在Worker onmessage回调后不会进行更改检测,我必须手动触发更改检测。

但在此之后,添加的选项卡中列表的背景在点击后不会发生变化(回调函数已执行,因此更改检测不起作用)。

如果我再次单击“添加标签”按钮,则更改检测将起作用并按预期设置列表背景。

如果我不手动触发变化检测。推动标签后,执行其他操作(例如,再次单击按钮)以触发更改检测。现在列表将显示,背景更改效果很好。

我知道密钥是在工人执行后手动调用更改检测,但我不知道详细情况发生了什么导致列表背景更改检测不起作用。

2 个答案:

答案 0 :(得分:2)

每次调用“添加”选项卡函数时,都在调用新工作程序。

addTab() {
      var worker = new Worker("worker.js");

相反,将此工作者声明为此类和范围的范围绑定变量。在函数中使用它。

 worker : any = new Worker("worker.js");
    addTab() {
      this.worker.postMessage("");
      this.worker.onmessage = (event) => {
      this.tabs.push({
         label: 'label'
      })

答案 1 :(得分:1)

NgZone修补了setTimeoutaddEventListener等异步API。当调用此类API的回调时,Angular会识别它并运行更改检测。

显然worker.onmessage未涵盖NgZone,因此不会调用更改检测。

有多种方法可以调用更改检测Triggering Angular2 change detection manually

detectChanges()仅调用当前元素的变化检测。 如果模型更改具有更广泛的影响(在组件外部),那么您可能需要运行应用程序范围的更改检测(例如,如果您从在Angulars区域外运行的回调router.navigate()(未由{{1}覆盖}。 在这种情况下,您可以使代码在区域内运行,如

NgZone