我的根本问题是我需要设置一个alters an attribute of the host的异步函数。由于@HostBinding没有异步功能,我在组件上设置了一个实例变量,绑定了该变量,并手动维护了该变量。为了让它在没有臭名昭着的ExpressionChangedAfterItHasBeenCheckedError的情况下工作,我需要这样做
@Component(...)
export class MyComponent implements OnChanges {
constructor(private readonly cdr: ChangeDetectorRef) {}
@Input() inputObservable: Observable<boolean>;
@HostBinding('class.some-class') private setCssClass: boolean;
ngOnChanges() {
this.inputObservable.do(v => {
if (this.setCssClass !== v) {
setTimeout(() => {
this.setCssClass = v;
this.cdr.detectChanges();
}, 0);
}
})
.subscribe();
}
}
这太糟糕了。
是否有一些更干净的方式告诉父母“这里有一个变量的新值,让你随意设置”?
修改
和它甚至都不起作用。在特殊情况下,setTimeout可以在组件被正式销毁之后执行,这导致异常需要整个“其他级别的hacky可怕性来防止。”
答案 0 :(得分:3)
您只需使用Renderer
方法进行ElementRef
即可。一旦组件被销毁,不要忘记取消订阅您的Observable:
@Component(...)
export class MyComponent implements OnInit, OnDestroy {
constructor(private element: ElementRef, private renderer: Renderer2) {}
@Input()
public inputObservable: Observable<boolean>;
private ngUnsubscribe = new Subject<void>()
ngOnInit() {
this.inputObservable
.takeUntil(this.ngUnsubscribe)
.do(v => this.toggleClass('some-class', v))
.subscribe()
}
ngOnDestroy() {
this.ngUnsubscribe.next();
this.ngUnsubscribe.complete();
}
private toggleClass(klass: string, state: boolean) {
if(!this.element.nativeElement) return;
if(state) {
this.renderer.addClass(this.element.nativeElement, klass)
} else {
this.renderer.removeClass(this.element.nativeElement, klass)
}
}
}
第二种方法是将组件的输入更改为boolean
,然后从父组件输入带有async
的observable - pipe:
@Input()
@HostBinding('class.some-class')
public myInput: boolean;
父组件
<my-component [myInput]="myObservable$ | async"></my-component>