Angular: 等到所有子组件都渲染完之后再写运行代码
Angular: Wait until all child components have rendered before running code
我有一个位于应用程序顶层的指令,它通过 document.querySelector
查询元素并将它们交给 fromEvent
。问题是,当指令的 ngAfterViewInit
运行 中的代码时,DOM 尚未完全呈现,因此元素查询 returns null.
我可以 运行 setTimeout
中的代码用任意时间,但这似乎不是一个可持续的、灵活的解决方案。
关于如何优雅地处理这个问题有什么想法吗?
现在,我的代码看起来像这样的一些变体:
ngAfterViewInit() {
const trackedEl = document.querySelector('#myInput');
const input$ = fromEvent(trackedEl, 'input')
.pipe(
map((inputEvent: any) => inputEvent.target.value)
)
.subscribe((v) => {
console.log(`Got to the observable:: ${v}`, count++);
})
}
我认为最好的方法是使用 ViewChild
.
之类的东西
因此,假设您的 querySelector 以 <input>
标记为目标,您的 html 就像(注意 #myInput 装饰器):
<input #myInput ....>
您的 .ts 文件将是:
@ViewChild('myInput', { static: true })
input?: ElementRef<HTMLElement>;
那么因为我们只想在事件订阅的时候解析:
const input$ = defer(() => fromEvent(this.input, 'input').pipe(
map((inputEvent: any) => inputEvent.target.value)
)
.subscribe((v) => {
console.log(`Got to the observable:: ${v}`, count++);
});
这方面的一些影响,但肯定 ViewChild
是这里的关键。
ngAfterViewInit 生命周期挂钩 angular 在它创建所有组件的子视图后调用。所以你必须在根 AppComponent 上实现它。
然后将可观察到服务或状态,并在任何你想检查的地方订阅它。
根 AppComponent:
export class AppComponent implements AfterViewInit {
title = "Angular App";
constructor(private data: DataService){}
ngAfterViewInit() {
this.data.rendered.next(true);
}
}
在任何地方订阅它:
export class HighlightDirective {
constructor(private data: DataService) {
this.data.rendered.subscribe(rendered => {
// all components rendered here, write you code
});
}
}
我认为这可能是一种方法:
ngAfterViewInit() {
defer(() => fromEvent(document.querySelector('#myInput'), 'input'))
.pipe(
subscribeOn(asyncScheduler),
map((inputEvent: any) => inputEvent.target.value)
)
.subscribe((v) => {
console.log(`Got to the observable:: ${v}`, count++);
})
}
这种方法仍然在使用类似 setTimeout
的东西,但是以更 优雅 的方式。这是通过使用 defer
+ subscribeOn
.
实现的
通过向 subscribeOn
提供 asyncScheduler
,我们获得了类似 setTimeout
的功能。使用 defer
运算符是因为我们要评估在订阅源时查询 DOM 的函数,并记得订阅时间被 subscribeOn
运算符延迟。
因此,在订阅源时,DOM 应该可以查询了。
我知道这只是 setTimeout
的一种变通方法,但我认为它看起来会更 花哨 一些有趣的 RxJS 运算符。
我最终找到了我正在寻找的解决方案。
子元素未及时呈现可能是因为它们正在响应一些尚未返回响应的未完成的 http 事件。在阅读了变更检测和 ngZone 的文档后,未完成的 http 事件似乎算作“微任务”。
下面的代码对我有用。
ngOnInit() {
this.ngZone.onMicrotaskEmpty.pipe(take(1)).subscribe((a) => {
this.initiateElementEventListeners();
});
}
我有一个位于应用程序顶层的指令,它通过 document.querySelector
查询元素并将它们交给 fromEvent
。问题是,当指令的 ngAfterViewInit
运行 中的代码时,DOM 尚未完全呈现,因此元素查询 returns null.
我可以 运行 setTimeout
中的代码用任意时间,但这似乎不是一个可持续的、灵活的解决方案。
关于如何优雅地处理这个问题有什么想法吗?
现在,我的代码看起来像这样的一些变体:
ngAfterViewInit() {
const trackedEl = document.querySelector('#myInput');
const input$ = fromEvent(trackedEl, 'input')
.pipe(
map((inputEvent: any) => inputEvent.target.value)
)
.subscribe((v) => {
console.log(`Got to the observable:: ${v}`, count++);
})
}
我认为最好的方法是使用 ViewChild
.
因此,假设您的 querySelector 以 <input>
标记为目标,您的 html 就像(注意 #myInput 装饰器):
<input #myInput ....>
您的 .ts 文件将是:
@ViewChild('myInput', { static: true })
input?: ElementRef<HTMLElement>;
那么因为我们只想在事件订阅的时候解析:
const input$ = defer(() => fromEvent(this.input, 'input').pipe(
map((inputEvent: any) => inputEvent.target.value)
)
.subscribe((v) => {
console.log(`Got to the observable:: ${v}`, count++);
});
这方面的一些影响,但肯定 ViewChild
是这里的关键。
ngAfterViewInit 生命周期挂钩 angular 在它创建所有组件的子视图后调用。所以你必须在根 AppComponent 上实现它。 然后将可观察到服务或状态,并在任何你想检查的地方订阅它。
根 AppComponent:
export class AppComponent implements AfterViewInit {
title = "Angular App";
constructor(private data: DataService){}
ngAfterViewInit() {
this.data.rendered.next(true);
}
}
在任何地方订阅它:
export class HighlightDirective {
constructor(private data: DataService) {
this.data.rendered.subscribe(rendered => {
// all components rendered here, write you code
});
}
}
我认为这可能是一种方法:
ngAfterViewInit() {
defer(() => fromEvent(document.querySelector('#myInput'), 'input'))
.pipe(
subscribeOn(asyncScheduler),
map((inputEvent: any) => inputEvent.target.value)
)
.subscribe((v) => {
console.log(`Got to the observable:: ${v}`, count++);
})
}
这种方法仍然在使用类似 setTimeout
的东西,但是以更 优雅 的方式。这是通过使用 defer
+ subscribeOn
.
通过向 subscribeOn
提供 asyncScheduler
,我们获得了类似 setTimeout
的功能。使用 defer
运算符是因为我们要评估在订阅源时查询 DOM 的函数,并记得订阅时间被 subscribeOn
运算符延迟。
因此,在订阅源时,DOM 应该可以查询了。
我知道这只是 setTimeout
的一种变通方法,但我认为它看起来会更 花哨 一些有趣的 RxJS 运算符。
我最终找到了我正在寻找的解决方案。
子元素未及时呈现可能是因为它们正在响应一些尚未返回响应的未完成的 http 事件。在阅读了变更检测和 ngZone 的文档后,未完成的 http 事件似乎算作“微任务”。
下面的代码对我有用。
ngOnInit() {
this.ngZone.onMicrotaskEmpty.pipe(take(1)).subscribe((a) => {
this.initiateElementEventListeners();
});
}