【问题标题】:View is not updated on change in Angular2Angular2 中的更改未更新视图
【发布时间】:2016-04-08 03:59:39
【问题描述】:

我已经开始探索 Angular2(我将使用 Angular1 和一些 React 背景),但遇到了一个问题。

我想将某些击键绑定到我的组件中的操作,所以我决定使用 Angular2 生命周期来绑定/取消绑定操作。

但是,如果我在 Mousetrap 回调中执行某些操作,它会起作用,但它不会被渲染,并且在运行摘要循环之前更改是不可见的。

我是否需要显式运行某些东西来更新视图

有人可以帮我弄清楚发生了什么吗? 任何帮助将不胜感激。


import {Component} from 'angular2/core';
const Mousetrap = require('mousetrap');

@Component({
  template: `<div>
    Video template: Mode {{ mode }}
    <input type="number" [(ngModel)]="mode"/>
  </div>`
})
export class Video {

  public mode: number;

  constructor() {
    this.mode = 0;
  }

  ngOnInit() {

    console.log('hello Video component');
    Mousetrap.bind('d', () => console.log('this.mode=', this.mode));
    Mousetrap.bind('i', () => this.incrementMode()); // doesn't work

    this.incrementMode(); // works
    this.incrementMode(); // works
    setTimeout(() => this.incrementMode(), 4000); // works

  }

  incrementMode() {
    console.log('incMode', this.mode++);
  };

  ngOnDestroy() {
    console.log('bye bye Video component');
    Mousetrap.unbind(['d', 'i']);
  }

}

【问题讨论】:

    标签: angular


    【解决方案1】:

    虽然@Günter 的回答绝对正确,但我想提出一个不同的解决方案。

    Mousetrap 库的问题在于它在角度zone 之外创建了它的实例(请参阅here)。但是要在每个异步事件之后触发更改检测,应该在 角度 zone 内实例化实例。您有两种选择来实现这一目标:

    1. 使用依赖注入:
    bootstrap(App, [provide(Mousetrap, { useFactory: () => new Mousetrap() }) ]);
    
    // ...
    
    @Component({
      selector: 'my-app', 
      // ...
    })
    export class App {
      constructor(@Inject(Mousetrap) mousetrap) {
        this.mousetrap = mousetrap;
        // ...
      }
      //...
    }
    
    1. 只需在构造函数中创建Mousetrap 的实例即可:
    @Component({
      selector: 'my-app', 
      // ...
    })
    export class App {
      constructor() {
        this.mousetrap = new Mousetrap();
        // ...
      }
      //...
    }
    

    在这两种情况下,您都可以像这样使用捕鼠器实例:

    ngOnInit() {
      this.mousetrap.bind('i', () => this.incrementMode()); // It works now!!!
      // ...
    }
    

    现在您无需在每个bind 调用中都使用ngZone.run()。在依赖注入的情况下,您还可以在应用程序的任何组件/服务中使用此 mousetrap 实例(不仅在 App 组件中)。

    this plunk。我在那里使用依赖注入。

    【讨论】:

    • 这是一个非常聪明的解决方案。它适用于那里的每个/大多数库吗?
    • @EricMartinez 好吧,有太多 js 库具有绝对疯狂的实现。所以我绝对不能保证这对每个/大多数图书馆都有效。但基本原则很简单:您必须确保在角度区域内调用了“异步相关”函数(例如 addEventListener)——仅此而已。
    • 谢谢。现在我终于明白 Savkin 的说法了:“Angular 2 使用 Zone.js 来知道什么时候需要这个检查。这意味着你不需要调用 scope.$apply 来与第三方库集成。” -- 来自The Core Concepts of Angular 2 博客文章,ZONES 部分。我在我的待解决/我不明白的清单上有一段时间了。 (我假设 Angular 2 等效于 Angular 1 的 scope.$apply 是 ApplicationRef.tick()。但如果我们使用这种技术,我们就不需要它。)
    • @MarkRajcok 不客气。我想说 angular2 的 ApplicationRef.tick() 相当于 angular1 的 $rootScope.$digest()ngZone.run(cb) 相当于 $rootScope.$apply(cb)changeDetectorRef.detectChanges() 相当于 $scope.$digest()
    【解决方案2】:

    如果 MouseTrap 是 Angular 之外的东西,您可能需要注入 NgZone 并像这样运行代码

      Mousetrap.bind('i', () => this.ngZone.run(() => this.incrementMode()));
    

    【讨论】:

    • 感谢您提供有关 NgZone 的信息,我让它像这样工作Mousetrap.bind('i', () =&gt; this.ngZone.run(() =&gt; this.incrementMode()));
    • 感谢您的反馈 :) 更新了我的答案。
    猜你喜欢
    • 1970-01-01
    • 2023-03-17
    • 2016-12-18
    • 1970-01-01
    • 1970-01-01
    • 2016-12-21
    • 2016-06-06
    • 2016-04-02
    • 1970-01-01
    相关资源
    最近更新 更多