简体   繁体   English

淘汰嵌套组件:$(document).ready()…在加载嵌套组件之前运行

[英]Knockout nested components: $(document).ready() … runs before nest component is loaded

So I have several nested knockout components: 因此,我有几个嵌套的剔除组件:

<component1>
   <component2>
   ....
   </component2>
</component1>

component1 is my own component, written by me, but component2 is a third party code and I am not supposed to change it. component1是我自己编写的组件,由我编写,但是component2是第三方代码,我不应该对其进行更改。 Here is the problem: 这是问题所在:

In $(document).ready() , I use jquery $('button').click(...) to assign click even handler to, say, all buttons, for simplicity. $(document).ready() ,为了简单起见,我使用jquery $('button').click(...)将click even处理函数分配给所有按钮。 The result it, only buttons inside component1 and outside component2 get the handler, and none of the button inside component2 has the handler (nothing happens when I click on them). 结果是,只有component1内部和外部component2内的按钮才获得处理程序,而component2内部的按钮都没有处理程序(当我单击它们时什么也没有发生)。

Note that component2 relies on (consumes) data from some ajax call, so this may delay its loading. 请注意,component2依赖(消耗)来自一些ajax调用的数据,因此这可能会延迟其加载。 Because ajax is async, so it's possible that $(document).ready() runs even before the ajax finishes, and therefore, the $('button').click(...) didn't catch the buttons inside components as they have not been rendered yet. 因为ajax是异步的,所以$(document).ready()甚至可能在ajax完成之前就运行了,因此$('button').click(...)并没有抓住组件内部的按钮他们还没有被渲染。

Additional problem: The viewmodel1 of component1 seems to always be empty when inside component2. 附加问题:在component2内部时,component1的viewmodel1似乎总是空的。 The context is correct; 上下文是正确的; it's just empty (for example: an array of the viewmodel1 is empty inside component2, not not empty when outside component2. 它只是空的(例如:viewmodel1的数组在component2内部为空,而在component2外部为空。

How to make all the buttons inside component2 get the handler? 如何使component2中的所有按钮都获得处理程序?

您应该使用事件委托 ,以便在设置触发器时不必显示DOM元素。

$(document).on('click', 'button', ...);

Try to use the jQuery feature of adding events handlers to any future element inside. 尝试使用将事件处理程序添加到其中的任何将来元素的jQuery功能。 Check the syntax on the code below. 检查以下代码的语法。

$(document).on("click", "div", function(){
    console.log(this.id);
});

Even if some div is not loaded yet, the click event will work on those elements. 即使尚未加载某些div,click事件也将在这些元素上起作用。

If you can't modify component2 and it doesn't provide you with a way to know when it's done loading then your only option is to loop until it's done loading. 如果您不能修改component2并且它没有为您提供一种方法来知道何时完成加载,那么您唯一的选择就是循环直到完成加载。 You can tell when it's done loading by testing for some class/id/etc that you know is inside the component. 您可以通过测试您知道组件内部的某些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);

Note that this is indeed a hack/workaround. 请注意,这确实是一个hack /解决方法。 You should probably be passing an "onClick" function into the component which would wire it up appropriately. 您可能应该将“ onClick”函数传递组件中,以将其适当地连接起来。

[Edit] [编辑]

This workaround is overkill for simply attaching click events. 对于仅附加点击事件,此解决方法是多余的。 The other answers cover how this can be accomplished using jQuery's event delegation. 其他答案涵盖了如何使用jQuery的事件委托来实现。 This workaround is only practical when you need to modify the component's template/viewModel after it's been created and you have no way to modify the component any other way . 仅当创建组件后需要修改组件的template / viewModel并且无其他方法修改组件时,才可以使用此解决方法

If the jQuery delegate event doesn't fit your scenario and you are using Knockout >= 3.5.0 , you have the childrenComplete binding parameter you can use on your component. 如果jQuery委托事件不适合您的情况,并且您正在使用Knockout> = 3.5.0 ,则您可以在组件上使用childrenComplete绑定参数。

I use it like that: 我这样使用它:

<script>
        window.componentReady= false;
        function onAccordionReady() {
            window.componentReady = true;
        }
</script>
<div data-bind="component: {name: 'my-component', childrenComplete: onComponentReady">
</div>

And on javascript, similar to CrimsonChris's answer but perhaps more performant: 在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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM