根据我对runOutsideAngular()
的理解,如果我需要运行一些不会触发Angular变化检测的东西,我需要使用这个函数。但是,我的代码不起作用;当我点击按钮时,UI正在改变,数字是2。
@Component({selector: 'my-cmp',
template: `<h1>{{num}}</h1>
<button (click)="onClick()">Change number</button>`})
class MyComponent implements OnChanges {
num = 1;
constructor(private _ngZone: NgZone ) {
}
onClick() {
this._ngZone.runOutsideAngular(() => {
this.num = 2;
}}));
}
}
答案 0 :(得分:13)
如果有任何事情导致更改检测,并且像(click)="onClick()"
这样的绑定事件确实会导致更改检测,那么Angular将检测到更改。
runOutsideAngular
并不意味着Angular不会看到更改,它只意味着以这种方式运行的代码不会导致更改检测,但由于click事件已经发生,因此在您的示例中它没有意义。
答案 1 :(得分:6)
如果您想阻止更改检测,则可以
1)订阅bcda
,如下所示:
ngZone.onMicrotaskEmpty
此处理程序将在import { NgZone, ChangeDetectorRef } from '@angular/core';
import 'rxjs/add/operator/first';
...
export class MyComponent {
constructor(private ngZone: NgZone, private cdRef: ChangeDetectorRef) {}
onClick() {
// to do something
this.cdRef.detach();
this.ngZone.onMicrotaskEmpty.first().subscribe(() => {
// reattach changeDetector after application.tick()
this.cdRef.reattach();
});
}
}
另请参阅 Plunker Example
2)使用这样的自定义指令:
Application.tick
然后在模板中你可以写:
@Directive({
selector: '[outSideEventHandler]'
})
class OutSideEventHandlerDirective {
private handler: Function;
@Input() event: string = 'click'; // pass desired event
@Output('outSideEventHandler') emitter = new EventEmitter();
constructor(private ngZone: NgZone, private elRef: ElementRef) {}
ngOnInit() {
this.ngZone.runOutsideAngular(() => {
this.handler = $event => this.emitter.emit($event);
this.elRef.nativeElement.addEventListener(this.event, this.handler);
});
}
ngOnDestory() {
this.elRef.nativeElement.removeEventListener(this.event, this.handler);
}
}
或
<button (outSideEventHandler)="onClick()">Click outside zone</button>
<强> Plunker 强>
3)编写自定义DOM事件处理程序,如本文所述。
其他解决方案请点击此处:
答案 2 :(得分:6)
[简而言之] 您需要更改当前代码中的一行
onClick() {
this._ngZone.runOutsideAngular(() => {
setTimeout(()=>this.num = 2,0); // instead of this.num = 2;
}}));
}
现在,如果您点击<button>
,this.num
将成为2
,但您不会看到任何更改(视图和模型之间的暂时不一致)< / p>
[说明] 没有runOutsideAngular()
,addEventListener()
或setTimeout()
等异步函数的行为方式不同(monkey patched)。他们的回调将在运行用户代码后尝试使用Angular更新UI。
例如,您可以将(click)="onClick()"
视为:
addEventListener("click",function modifiedCallback(){
onClick();
updateUIifModelChanges(); //call to Angular
})
为了不触发UI更新,我们需要满足以下两个条件:
onClick
中的模型(因此,在setTimeout()
内修改)updateUIifModelChanges
(在setTimeout()
内调用runOutsideAngular
) [更多] 的原因,我给出的解释是一个非常非常简化的版本。 setTimeout()
具有相同的函数签名,无论它是否在runOutsideAngular()
内运行。它表现不同的原因是因为它在不同的Zone
答案 3 :(得分:4)
使用ngZone.run
比setTimeout
解决方案要好一些,因为它使用了角度特定的功能。运行意味着在ngZone.runOutsideAngular
函数中使用。
来自文档:
通过run运行函数允许您从a重新进入Angular区域 在Angular区域外执行的任务(通常开始 通过{@link #runOutsideAngular})。
这实际上是一个非常实用的例子,比如说一个按钮会将数字增加一个,但只有当数字是偶数时才触发更改检测。
@Component({selector: 'my-cmp',
template: `<h1>{{num}}</h1>
<button (click)="onClick()">Change number</button>`})
class MyComponent implements OnChanges {
num = 1;
constructor(private _ngZone: NgZone ) {
}
onClick() {
this._ngZone.runOutsideAngular(() => {
if(this.num % 2 === 0){
// modifying the state here wont trigger change.
this.num++;
} else{
this._ngZone.run(() => {
this.num++;
})
}
}}));
}
}
&#13;
答案 4 :(得分:0)
...
constructor(
private ngZone: NgZone
){
ngZone.runOutsideAngular(() => {
setInterval(()=>{
this.num= new Date().Format('yyyy-MM-dd HH:mm:ss');
},1000);
});
}
...
答案 5 :(得分:0)
这就是我试图检查 insideAngular 和 OutsideAngular 的区别
constructor(private zone: NgZone) { }
setProgressOutsideAngular() {
this.zone.runOutsideAngular(() => {
setInterval(() => { ++this.progress, console.log(this.progress) }, 500)
})
}
setProgressInsideAngular() {
this.zone.run(() => setInterval(() => { ++this.progress, console.log(this.progress) }, 500))
}