sin*_*sem 172 angular2-changedetection angular
显示模板中相应元素后获取@ViewChild最优雅的方法是什么?以下是一个例子.也有Plunker可用.
模板:
<div id="layout" *ngIf="display">
<div #contentPlaceholder></div>
</div>
Run Code Online (Sandbox Code Playgroud)
零件:
export class AppComponent {
display = false;
@ViewChild('contentPlaceholder', {read: ViewContainerRef}) viewContainerRef;
show() {
this.display = true;
console.log(this.viewContainerRef); // undefined
setTimeout(()=> {
console.log(this.viewContainerRef); // OK
}, 1);
}
}
Run Code Online (Sandbox Code Playgroud)
我有一个默认隐藏其内容的组件.当有人调用@ViewChild方法时,它变得可见.但是,在角度2变化检测完成之前,我无法参考show().我通常将所有必需的操作包装成viewContainerRef如上所示.有更正确的方法吗?
我知道有一个选项setTimeout(()=>{},1),但它会导致太多无用的通话.
par*_*ent 279
使用QueryList接受的答案对我不起作用.然而,有什么工作是使用ViewChild的setter:
private contentPlaceholder: ElementRef;
@ViewChild('contentPlaceholder') set content(content: ElementRef) {
this.contentPlaceholder = content;
}
Run Code Online (Sandbox Code Playgroud)
一旦*ngIf变为真,就会调用setter.
Jef*_*ima 94
克服这个问题的另一种方法是手动运行变化检测器.
你先注入ChangeDetectorRef:
constructor(private changeDetector : ChangeDetectorRef) {}
Run Code Online (Sandbox Code Playgroud)
然后在更新控制*ngIf的变量后调用它
show() {
this.display = true;
this.changeDetector.detectChanges();
}
Run Code Online (Sandbox Code Playgroud)
小智 21
上面的答案对我不起作用,因为在我的项目中,ngIf在输入元素上.我需要访问nativeElement属性,以便在ngIf为true时关注输入.ViewContainerRef上似乎没有nativeElement属性.这是我做的(遵循@ViewChild文档):
<button (click)='showAsset()'>Add Asset</button>
<div *ngIf='showAssetInput'>
<input #assetInput />
</div>
...
private assetInputElRef:ElementRef;
@ViewChild('assetInput') set assetInput(elRef: ElementRef) {
this.assetInputElRef = elRef;
}
...
showAsset() {
this.showAssetInput = true;
setTimeout(() => { this.assetInputElRef.nativeElement.focus(); });
}
Run Code Online (Sandbox Code Playgroud)
我在聚焦之前使用了setTimeout,因为ViewChild需要一秒钟来分配.否则它将是未定义的.
Svi*_*siv 19
角度8
您应该添加{ static: false }第二个选项@ViewChild
例:
export class AppComponent {
@ViewChild('contentPlaceholder', { static: false }) contentPlaceholder: ElementRef;
display = false;
constructor(private changeDetectorRef: ChangeDetectorRef) {
}
show() {
this.display = true;
this.changeDetectorRef.detectChanges();
console.log(this.contentPlaceholder);
}
}
Run Code Online (Sandbox Code Playgroud)
Stackblitz示例:https://stackblitz.com/edit/angular-d8ezsn
use*_*728 11
正如其他人所提到的,最快和最快的解决方案是使用[hidden]而不是*ngIf,这样组件将被创建但不可见,因为你可以访问它,尽管它可能不是最有效的办法.
这可行,但我不知道你的情况是否方便:
@ViewChildren('contentPlaceholder', {read: ViewContainerRef}) viewContainerRefs: QueryList;
ngAfterViewInit() {
this.viewContainerRefs.changes.subscribe(item => {
if(this.viewContainerRefs.toArray().length) {
// shown
}
})
}
Run Code Online (Sandbox Code Playgroud)
另一个快速的“技巧”(简单的解决方案)只是使用[hidden]标记而不是* ngIf,重要的是要知道在这种情况下Angular构建对象并将其绘制在class下:hidden,这就是为什么ViewChild可以正常工作的原因。 因此,请务必记住,不要在可能导致性能问题的笨重或昂贵物品上使用隐藏物品
<div class="addTable" [hidden]="CONDITION">
Run Code Online (Sandbox Code Playgroud)
我的目标是避免任何假设某些东西的 hacky 方法(例如 setTimeout),我最终实现了带有一点RxJS风味的公认解决方案:
private ngUnsubscribe = new Subject();
private tabSetInitialized = new Subject();
public tabSet: TabsetComponent;
@ViewChild('tabSet') set setTabSet(tabset: TabsetComponent) {
if (!!tabSet) {
this.tabSet = tabSet;
this.tabSetInitialized.next();
}
}
ngOnInit() {
combineLatest(
this.route.queryParams,
this.tabSetInitialized
).pipe(
takeUntil(this.ngUnsubscribe)
).subscribe(([queryParams, isTabSetInitialized]) => {
let tab = [undefined, 'translate', 'versions'].indexOf(queryParams['view']);
this.tabSet.tabs[tab > -1 ? tab : 0].active = true;
});
}
Run Code Online (Sandbox Code Playgroud)
我的场景:我想@ViewChild根据 router在元素上触发一个动作queryParams。由于*ngIf在 HTTP 请求返回数据之前包装是假的,@ViewChild元素的初始化发生延迟。
它是如何工作的: combineLatest仅当每个提供的 Observable 发出自combineLatest订阅时刻以来的第一个值时,才第一次发出一个值。tabSetInitialized当设置@ViewChild元素时,我的主题会发出一个值。因此,我延迟了代码的执行,subscribe直到*ngIf变为正值并@ViewChild初始化。
当然不要忘记在 ngOnDestroy 上取消订阅,我是使用ngUnsubscribeSubject来做的:
ngOnDestroy() {
this.ngUnsubscribe.next();
this.ngUnsubscribe.complete();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
68750 次 |
| 最近记录: |