angular-安全地获取延迟加载的DOM元素的引用

时间:2018-07-19 17:04:33

标签: angular dom rxjs

我有一个模板部分,仅当对应的对象存在时才在DOM中。此外,我想获取表单引用,并向其附加一个fromEvent('change')Observable。

由于数据可能会在ngAfterViewInit之后到达,因此将没有要获取的引用。

查看

<div *ngIf="user$ | async">
    <form id="form" #form></form>
</div>

组件

@ViewChild('form') form;

ngOnInit(){
    this.user$ = this.someService.getUser() // returns Observable<User>
}

ngAfterViewInit(){
    const form = document.getElementById('form')
    fromEvent(form || this.form,'change')...
}

我也尝试将其移至可观察对象的回调

   ngAfterViewInit(){
        this.user$ = this.someService.getUser().pipe(map(res => {
            const form = document.getElementById('form')
            fromEvent(form || this.form,'change')...
            return res
        }))
    }

建议任何涉及setTimeout()的解决方案

2 个答案:

答案 0 :(得分:2)

在您的代码中使用

@ViewChild('form') form;

基本上说“在Component中定义实例变量form,并将其值设置为#form所标识的任何DOM元素。

一旦创建了#form所标识的元素,Angular就会设置实例变量form的值。

重点是您在ngAfterViewInit中说

ngAfterViewInit(){
    const form = document.getElementById('form')
    fromEvent(form || this.form,'change')...
}

这表示您要设置一个变量form,该变量仅在ngAfterViewInit方法中可见,且其元素的值为form

ngAfterViewInit运行时,该元素可能还不存在,并且您真的不知道何时创建。顺便说一句,您还创建了第二个变量form,该变量仅在ngAfterViewInit中可见,以容纳应由this.form持有的同一事物,即Component实例变量。

您可以考虑删除@ViewChild('form') form;代码和ngAfterViewInit逻辑,然后将事件formChanged添加到html元素(例如

)中
<div *ngIf="user$ | async">
    <form id="form" (changed)="formChanged($event)"></form>
</div>

然后实现方法formChaged(event)来完成您需要做的所有事情。

答案 1 :(得分:0)

@Picci的回答正确地表明,对于您发布的代码,您应该仅在form标记上使用(已更改的)Angular事件,而不是直接挂接到DOM。但是,如果确实需要如前所述获得对延迟加载的组件的引用,则需要执行以下操作:

formInitialised: bool = false;

// Implement AfterViewChecked to run this each time the view
// changes - note this will run many times, so you need to keep
// track of whether you have done whatever form initialisation
// you need.
ngAfterViewChecked() {
    // Check if form is now defined
    if (this.form && !this.formInitialised) {
        // Do whatever you need to do with this.form
        this.formInitialised = true;
    }
    // If the form has disappeared from the page, update
    // our flag to say so.
    if (!this.form && this.formInitialised) this.formInitialised = false;
}