为什么将代码置于setTimeout中使Angular正常工作?

时间:2018-03-08 20:31:46

标签: javascript angular settimeout

我一直在尝试在Angular 5中创建一个简单的指令,但是在墙壁上。我最近发现在setTimeout函数中添加我的代码使它按预期工作。在这种情况下,我希望表单显示为" yolo"

我不完全理解为什么。我知道它与Angular bootstraps的方式有关,但我不明白为什么会这样 - 特别是为什么构造函数中的代码被丢弃(毕竟,那么构造函数的重点是什么) ?)

请在下面找到相关代码的简化副本:

With setTimeout

Without 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 {}

2 个答案:

答案 0 :(得分:4)

当你将代码置于setTimeout中时,你实际上将它从当前的调用堆栈中取出,一旦整个调用堆栈被执行,事件循环将选择你的代码并将它放在一个新的调用堆栈之上并执行开始。当调用堆栈完成时,你可以绕过术语tick,这就是勾号。在你的情况下,setTimeout基本上是0ms,但代码从当前堆栈中删除,所以其他一切都完成,然后你的代码运行,修改属性和角度变化检测器检测到变化。

答案 1 :(得分:1)

在构建指令时,Angular不检查指令(或其主机组件)属性的更改。在将相关代码移动到setTimeout的同时,在例如中执行此类操作会更好(即,不是一个hacky解决方法)。 ngOnInit

// PhoneMask implements OnInit
ngOnInit() {
  this.model.valueAccessor.writeValue('yolo')
}

值得一读:https://stackoverflow.com/a/35763811/7178441

更新:@csmckelvey在评论中解释了为什么setTimeout技巧确实有效:

  

因为它会导致代码被延迟,直到执行构造函数之后。