我在做什么
我有一个基于简单布尔值使用concat
隐藏/显示的组件。当组件变得可见时,我想将焦点应用于其模板中的子元素。
问题
如果我翻转布尔值,组件会正确显示,但如果我尝试使用#photos li {
width: 30%;
float: left;
display: block;
margin: 1px;
}
#photos img {
max-width: 100%
}
获取对子元素的引用,则只返回*ngIf
。如果我等待几秒钟,相同的代码将返回对我所期望的元素的引用。
投机
我假设在翻转后,布尔角度经过整个渲染周期以显示新的可见组件,并且在我在下一行中应用this._elRef.nativeElement.querySelector("div#test")
时尚未完成。
我想知道
所以我想知道的是,我怎样才能确定我的null
已经生效并且元素是他们在DOM中的选择?是否存在回调等问题querySelector()
或者我可以强制视图更新并从中获取回调吗?
我希望这是有道理的。这是一个漫长的一天(漫长的一周),我非常累。
谢谢所有
如果有帮助,我使用的是Angular2 v2.0.0-beta.15
答案 0 :(得分:24)
如果将布尔值翻转为true
并在下一行代码中尝试获取对由NgIf控制的组件或DOM元素的引用...那么,该组件或DOM元素不会#39但是还存在。 Angular并不与您的代码并行运行。您的JavaScript回调必须完成,然后运行Angular(更改检测),这将注意到布尔值的更改并创建组件或DOM元素并将其插入DOM。
要解决您的问题,请在翻转布尔值后调用setTimeout(callbackFn, 0)
。这会将callbackFn
添加到JavaScript message queue。这将确保Angular(更改检测)在回调函数之前运行。因此,当您callbackFn
执行时,您想要关注的元素现在应该存在。使用setTimeout(..., 0)
可确保在JavaScript event loop的下一回合调用callbackFn
。
在讨论AfterView* hooks时,LifeCycle钩子开发指南中使用了setTimeout(..., 0)
这种使用技巧。
如果您需要更多详细信息,请参阅以下几个示例:
focus
答案 1 :(得分:8)
这个问题相当陈旧,当时可能还没有当前的解决方案。
setTimeout()
方法完全可行,但有明显的缺点。如果你只是设置一个类来定位元素,就像我一样,你得到一个跳跃的结果,因为代码是在角度循环之后执行的。
使用ChangeDetectorRef
会产生不跳跃的结果。
所以不要这样:
class Foo {
public isDisplayed = false;
constructor(@Inject(ElementRef) private elementRef: ElementRef) {
}
public someMethod(): void {
this.isDisplayed = true;
setTimeout(() => {
const child = this.elementRef.nativeElement.querySelector('.child-element');
// ...
});
}
}
你可以这样做:
class Foo {
public isDisplayed = false;
constructor(@Inject(ElementRef) private elementRef: ElementRef,
@Inject(ChangeDetectorRef) private changeDetectorRef: ChangeDetectorRef) {
}
public someMethod(): void {
this.isDisplayed = true;
this.changeDetectorRef.detectChanges();
const child = this.elementRef.nativeElement.querySelector('.child-element');
// ...
}
}