[英]Why does putting code inside a setTimeout make Angular work properly?
I've been trying to create a simple directive in Angular 5 but hit walls. 我一直在尝试在Angular 5中创建一个简单的指令,但遇到了麻烦。 I recently discovered that adding my code inside a
setTimeout
function makes it work as I expect. 我最近发现,将我的代码添加到
setTimeout
函数中可以使其按预期工作。 In this case I expect the form to appear populated with " yolo
" 在这种情况下,我希望表单显示为“
yolo
”
I don't completely understand why. 我不完全明白为什么。 I understand that it has to do with the way Angular bootstraps but I don't understand why it is that way - and especially why code in the constructor is discarded (After all, then what's the point of the constructor?)
我知道这与Angular Bootstraps的方式有关,但我不明白为什么会这样-尤其是为什么丢弃构造函数中的代码(毕竟,构造函数的意义是什么?)
Please find a simplified copy of the code in question below: 请在下面找到相关代码的简化副本:
Without setTimeout 没有setTimeout
@Directive({
selector: '[formControlName][phone]',
host: {
'(ngModelChange)': 'onInputChange($event)'
}
})
export class PhoneMask {
constructor(public model: NgControl) {
// with setTimeout
setTimeout(() => {
this.model.valueAccessor.writeValue('yolo');
});
// without setTimeout
// this.model.valueAccessor.writeValue('yolo');
}
}
@Component({
selector: 'my-app',
providers: [],
template: `
<form [formGroup]="form">
<input type="text" phone formControlName="phone">
</form>
`,
directives: [PhoneMask]
})
export class App {
constructor(fb:FormBuilder) {
this.form=fb.group({
phone:['']
})
}
}
@NgModule({
imports: [ BrowserModule, FormsModule, ReactiveFormsModule ],
declarations: [ App, PhoneMask ],
bootstrap: [ App ]
})
export class AppModule {}
When you put code in a setTimeout you are effectively taking it out of the current call stack, once the whole call stack is executed the event loop will pick your code and put it on top of a new call stack and the execution will start. 当将代码放入setTimeout中时,实际上是将其从当前调用堆栈中删除,一旦执行了整个调用堆栈,事件循环就会选择您的代码并将其放在新的调用堆栈之上,然后开始执行。 You may come around the term tick, well thats a tick, when the call stack is done.
调用堆栈完成后,您可能会碰到术语“滴答”,也就是“滴答”。 In your case, setTimeout is basically 0ms but the code is removed from the current stack, so everything else completes, then your code runs, modifies the property and angular change detector detects the change.
在您的情况下,setTimeout基本上为0ms,但是代码已从当前堆栈中删除,因此其他所有操作都将完成,然后您的代码运行,修改属性并由角度变化检测器检测到变化。
At the time of constructing your directive, Angular doesn't check for changes in the directive's (or rather its host component's) properties. 在构造指令时,Angular不会检查指令(或它的宿主组件)属性中的更改。 While moving the relevant code to
setTimeout
works, it's much better (ie. not a hacky workaround) to do such things in eg. 在将相关代码移至
setTimeout
,例如在进行此类操作时要好得多(即,不是一个棘手的解决方法)。 ngOnInit
: ngOnInit
:
// PhoneMask implements OnInit
ngOnInit() {
this.model.valueAccessor.writeValue('yolo')
}
Worth reading: https://stackoverflow.com/a/35763811/7178441 值得一读: https : //stackoverflow.com/a/35763811/7178441
Update: @csmckelvey explained in comments why the setTimeout
trick actually works: 更新:@csmckelvey在注释中解释了
setTimeout
技巧实际上起作用的原因:
Because it causes the code to be delayed until after the constructor has been executed.
因为这会导致代码延迟到构造函数执行之后。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.