Просмотр не обновляется при изменении 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;
// ...
}
//...
}
- Просто создайте экземпляр
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()));