Просмотр не обновляется при изменении Angular2

Я начал изучать 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']);
  }

}

Ответ 1

Хотя ответ @Günter абсолютно правильный, я хочу предложить другое решение.

Проблема с библиотекой Mousetrap заключается в том, что она создает свой экземпляр вне angular zone (см. здесь). Но для обнаружения изменений при каждом асинхронном событии экземпляр должен быть создан внутри angular zone. У вас есть два варианта:

  • Используйте инъекцию зависимостей:
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();
    // ...
  }
  //...
}

В обоих случаях у вас будет возможность использовать экземпляр mousetrap следующим образом:

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

Теперь вам не нужно использовать ngZone.run() в каждом вызове bind. В случае инъекции зависимостей вы также можете использовать этот экземпляр Mousetrap в любом компоненте/службе вашего приложения (не только в компоненте App).

Смотрите эту панель. Я использую там инъекцию зависимостей.

Ответ 2

Если MouseTrap является чем-то вне Angular, вам может потребоваться ввести NgZone и запустить ваш код, например

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