如何检查ngIf是不是生效
Posted
技术标签:
【中文标题】如何检查ngIf是不是生效【英文标题】:How to check whether ngIf has taken effect如何检查ngIf是否生效 【发布时间】:2016-09-18 06:07:05 【问题描述】:我在做什么
我有一个基于简单布尔值使用*ngIf
隐藏/显示的组件。当组件变得可见时,我想将焦点应用到其模板中的子元素。
问题
如果我翻转布尔值,组件会正确显示,但如果我尝试使用this._elRef.nativeElement.querySelector("div#test")
获取对子元素的引用,它只会返回null
。如果我等待几秒钟,相同的代码将按预期返回对元素的引用。
推测
我假设在翻转布尔角度后会经历一个完整的渲染周期以显示新可见的组件,并且当我在下一行应用 querySelector()
时这还没有完成。
我想知道的
所以我想知道的是,我怎样才能确定我的ngIf
已经生效并且元素是它们在要选择的 DOM 中的?是否有 ngIf
的回调之类的东西或者可以我强制视图更新并从中获取回调?
我希望这是有道理的。这是漫长的一天(漫长的一周),我超级累。谢谢大家
如果有帮助,我正在使用 Angular2 v2.0.0-beta.15
【问题讨论】:
【参考方案1】:如果您将布尔值翻转为true
并在下一行代码中尝试获取对由 NgIf 控制的组件或 DOM 元素的引用......那么,该组件或 DOM 元素还不存在. Angular 不会与您的代码并行运行。您的 javascript 回调必须完成,然后 Angular(更改检测)运行,它会注意到布尔值更改并创建组件或 DOM 元素并将其插入 DOM。
要解决您的问题,请在翻转布尔值后调用 setTimeout(callbackFn, 0)
。这会将您的callbackFn
添加到JavaScript message queue。这将确保 Angular(更改检测)在您的回调函数之前运行。因此,当您的callbackFn
执行时,您要关注的元素现在应该存在。使用setTimeout(..., 0)
可确保您的callbackFn
在JavaScript event loop 的下一轮被调用。
LifeCycle hooks 开发指南中讨论AfterView* hooks 时使用了这种使用setTimeout(..., 0)
的技术。
如果您需要更多详细信息,这里还有一些其他示例:
https://***.com/a/35752722/215945 - 使用焦点() https://***.com/a/34757864/215945 - 使用渲染器调用focus
https://***.com/a/36338181/215945 - 使用指令设置焦点
https://***.com/a/34503163/215945 - 展示了 4 种不同的方法
【讨论】:
setTimeout()
解决方案有多强大?它使用延迟 0 解决了我的问题,但这感觉有点 hacky。超时是否与其余代码完全分开,因此有时视图更新需要更长的时间来呈现并且需要增加延迟?
@popClingwrap,请查看我的答案编辑。我试图添加更多细节。使用setTimeout()
一点也不笨拙,而且很健壮。这是延迟执行某些代码的常规 JavaScript 方式。在这种情况下,我们需要将焦点推迟到 Angular 创建 DOM 元素之后。不应该有任何“更长的渲染”案例。 Angular 更改检测所做的任何 DOM 更改都应该始终是事件循环的一个回合。
关于 Javascript 的实际内容,这是一些我以前不知道的有趣的东西。感谢您添加的细节,它确实有帮助,并提供了一大堆新内容供您阅读并被 :) 弄糊涂了:)
我今天遇到了这个问题......我花了一段时间才弄清楚发生了什么,并花了很长时间才找到提供解决方案的线程。代码执行速度比 DOM 渲染速度快,因此由于 DOM 元素尚不存在而导致错误。这个 setTimeout 成功了……更重要的是,我对 setTimeout 有了更深入的了解。谢谢!【参考方案2】:
这个问题比较老了,当时可能还没有当前的解决方案。
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');
// ...
【讨论】:
非常好。你手动触发 Angular 变化检测,然后定位你的元素——所有这些都在浏览器实际呈现之前。 太棒了 this.changeDetectorRef.detectChanges();完美无瑕。 这就是我要找的!谢谢!以上是关于如何检查ngIf是不是生效的主要内容,如果未能解决你的问题,请参考以下文章