所以我有几个嵌套的淘汰组件:
<component1>
<component2>
....
</component2>
</component1>
component1是我自己的组件,由我编写,但component2是第三方代码,我不应该更改它。这是问题所在:
在$(document).ready()
中,为了简单起见,我使用jquery $('button').click(...)
将click even处理程序分配给所有按钮。结果是,只有component1和component2中的按钮才能获得处理程序,而component2中的按钮都没有处理程序(当我点击它们时没有任何反应)。
请注意,component2依赖于(使用)来自某个ajax调用的数据,因此这可能会延迟其加载。因为ajax是异步的,所以$(document).ready()可能在ajax完成之前运行,因此,$('button').click(...)
没有抓住组件内的按钮,因为它们有尚未渲染。
其他问题:在component2内部,component1的viewmodel1似乎总是为空。背景是正确的;它只是空的(例如:viewmodel1的数组在component2中是空的,当在component2之外时不是空的。
如何让component2中的所有按钮获得处理程序?
答案 0 :(得分:2)
您应该使用event delegation,以便在设置触发器时不必存在DOM元素。
$(document).on('click', 'button', ...);
答案 1 :(得分:2)
尝试使用jQuery功能将事件处理程序添加到其中的任何未来元素。检查下面代码的语法。
$(document).on("click", "div", function(){
console.log(this.id);
});
即使尚未加载某些div,click事件也会对这些元素起作用。
答案 2 :(得分:1)
如果您无法修改component2并且它没有为您提供了解何时完成加载的方法,那么您唯一的选择是循环直到它完成加载。你可以通过测试你知道在组件内的一些class / id / etc来判断它何时完成加载。
<component1>
<component2>
...
<div class="some-class-I-know-will-be-here"></div>
</component2>
</component1>
var loop = window.setInterval(function () {
if ($('.some-class-I-know-will-be-here')[0]) {
componentHasLoaded();
window.clearInterval(loop);
}
}, 100);
请注意,这确实是一个黑客/解决方法。您可能应该将“onClick”函数传递给组件,该组件将适当地连接它。
<强> [编辑] 强>
这种解决方法对于简单地附加点击事件来说太过分了。其他答案涵盖了如何使用jQuery的事件委托来完成。只有当您需要在创建组件的模板/ viewModel之后修改它并且无法以任何其他方式修改组件时,此解决方法才是实用的。
答案 3 :(得分:0)
如果jQuery委托事件不适合您的场景并且您使用的是Knockout&gt; = 3.5.0
,那么您可以在组件上使用childrenComplete
绑定参数。
我这样使用它:
<script>
window.componentReady= false;
function onAccordionReady() {
window.componentReady = true;
}
</script>
<div data-bind="component: {name: 'my-component', childrenComplete: onComponentReady">
</div>
在javascript上,类似于CrimsonChris的答案,但也许更高效:
<script>
$(document).ready(function documentReady() { //Notice the named function
if (!window.componentLoaded) {
setTimeout(documentReady, 1000);
return; //Don't forget the return!
}
//... All the code I want to execute on document ready that
//dependent on the components having finished rendering
}
</script>