angular *ngIf 语句在模板中计算时触发的事件
Event to fire when an angular *ngIf statement evaluates in template
如果我有以下情况:
<div *ngIf="user$ | async as user" class="container">
<p>{{user.name}}</p>
</div>
当上面的 div
最终出现在屏幕上时,有什么方法可以执行代码吗?
*ngIf
将删除 DOM 元素和所有附加的 components/directives。所以你可以只写一个简单的指令,在事件第一次创建时执行它。当 *ngIf
从 false 转换为 true 时,将创建指令(一次又一次,等等...)
@Directive({selector: '[after-if]'})
export class AfterIfDirective implements AfterContentInit {
@Output('after-if')
public after: EventEmitter<void> = new EventEmitter<void>();
public ngAfterContentInit(): void {
// timeout helps prevent unexpected change errors
setTimeout(()=> this.after.next());
}
}
样本HTML:
<div *ngIf="user$ | async as user" (after-if)="your expression">
<p>{{user.name}}</p>
</div>
不创建新指令的解决方案是利用@ViewChild
和@ViewChildren
行为:
Property decorator that configures a view query. The change detector
looks for the first element or the directive matching the selector in
the view DOM. If the view DOM changes, and a new child matches the
selector, the property is updated.
1。 ViewChild
重要的部分是 如果视图 DOM 发生变化 这意味着在这种情况下只会触发当元素被创建或销毁时。
首先为元素声明一个变量名,对于我使用的示例#userContent
<div #userContent *ngIf="user$ | async as user" class="container">
<p>user.name</p>
</div>
然后在您的组件中添加一个 @ViewChild
引用:
@ViewChild('userContent') set userContent(element) {
if (element) {
// here you get access only when element is rendered (or destroyed)
}
}
此解决方案在 another question, also @ViewChild
behaviour detail is available here.
中提供
2。查看子项
另一种不使用新指令的解决方案是订阅
@ViewChildren
更改 observable,而不是使用 @ViewChild
像这样:
@ViewChildren('userContent')
private userContent: QueryList<any>;
然后订阅它改变 observable:
userContent.changes.pipe(takeUntil(this.$d)).subscribe((d: QueryList<any>) => {
if (d.length) {
// here you get access only when element is rendered
}
});
我更喜欢最后一种方法,因为对我来说,处理可观察对象比处理内部验证更容易 setter's
,而且这种方法更接近“事件”概念。
关于 Observable 的注意事项:
所有可观察对象都需要取消订阅,否则会引起内存泄漏;有很多方法可以防止这种情况发生,作为建议,我最喜欢的方法是 RxJs 函数 takeUntil
,这部分:pipe(takeUntil(this.$d))
以及 ngOnDestroy
方法中的以下内容:
private $d = new Subject();
ngOnDestroy() {
this.$d.next();
this.$d.complete();
}
我推荐这种方式的原因也是因为实现它的额外代码量非常少; 您可以对组件中的所有订阅 使用相同的变量 (this.$d
)。有关 details/options 取消订阅方法的更多信息,请参阅 。
如果我有以下情况:
<div *ngIf="user$ | async as user" class="container">
<p>{{user.name}}</p>
</div>
当上面的 div
最终出现在屏幕上时,有什么方法可以执行代码吗?
*ngIf
将删除 DOM 元素和所有附加的 components/directives。所以你可以只写一个简单的指令,在事件第一次创建时执行它。当 *ngIf
从 false 转换为 true 时,将创建指令(一次又一次,等等...)
@Directive({selector: '[after-if]'})
export class AfterIfDirective implements AfterContentInit {
@Output('after-if')
public after: EventEmitter<void> = new EventEmitter<void>();
public ngAfterContentInit(): void {
// timeout helps prevent unexpected change errors
setTimeout(()=> this.after.next());
}
}
样本HTML:
<div *ngIf="user$ | async as user" (after-if)="your expression">
<p>{{user.name}}</p>
</div>
不创建新指令的解决方案是利用@ViewChild
和@ViewChildren
行为:
Property decorator that configures a view query. The change detector looks for the first element or the directive matching the selector in the view DOM. If the view DOM changes, and a new child matches the selector, the property is updated.
1。 ViewChild
重要的部分是 如果视图 DOM 发生变化 这意味着在这种情况下只会触发当元素被创建或销毁时。
首先为元素声明一个变量名,对于我使用的示例#userContent
<div #userContent *ngIf="user$ | async as user" class="container">
<p>user.name</p>
</div>
然后在您的组件中添加一个 @ViewChild
引用:
@ViewChild('userContent') set userContent(element) {
if (element) {
// here you get access only when element is rendered (or destroyed)
}
}
此解决方案在 another question, also @ViewChild
behaviour detail is available here.
2。查看子项
另一种不使用新指令的解决方案是订阅
@ViewChildren
更改 observable,而不是使用 @ViewChild
像这样:
@ViewChildren('userContent')
private userContent: QueryList<any>;
然后订阅它改变 observable:
userContent.changes.pipe(takeUntil(this.$d)).subscribe((d: QueryList<any>) => {
if (d.length) {
// here you get access only when element is rendered
}
});
我更喜欢最后一种方法,因为对我来说,处理可观察对象比处理内部验证更容易 setter's
,而且这种方法更接近“事件”概念。
关于 Observable 的注意事项:
所有可观察对象都需要取消订阅,否则会引起内存泄漏;有很多方法可以防止这种情况发生,作为建议,我最喜欢的方法是 RxJs 函数 takeUntil
,这部分:pipe(takeUntil(this.$d))
以及 ngOnDestroy
方法中的以下内容:
private $d = new Subject();
ngOnDestroy() {
this.$d.next();
this.$d.complete();
}
我推荐这种方式的原因也是因为实现它的额外代码量非常少; 您可以对组件中的所有订阅 使用相同的变量 (this.$d
)。有关 details/options 取消订阅方法的更多信息,请参阅