在后端添加小部件时执行Javascript


20

我有附加了javascript控件的小部件。

如果在窗口小部件管理页面加载时窗口小部件存在,则控件可以正常工作。

当我添加新的小部件时,它们无法正常工作,我得到了标记,但是没有任何JavaScript事件生效。

如果我保存了新的小部件,则在重新加载表单时,控件将正确创建并且可以正常工作。

刷新页面也可以解决此问题,但仅适用于现有窗口小部件。新的小部件仍然存在此问题。

具体来说,我在这些时候对选择输入运行selectize:

  • 准备好文件
  • Ajaxcomplete

我已经验证我的代码可以按需在每个事件上运行,但是结果却不符合预期。

这是一个演示该问题的测试插件:

https://gist.github.com/Tarendai/8466299

您会看到我有一个计数器,它发现它可以转换的每个select元素都会增加。

笔记:

  • 加载小部件页面后,我可以看到JS控制台中的计数器正在按预期方式增加
  • 当我添加一个新的小部件时,代码将运行,但是,它找不到能在其上运行的所有选择元素,如found.length为0所示。情况并非如此,因为该类型的每个新小部件都应有一个选择元素
  • select元素具有一个用于标识它们的类,一旦应用了selectize库,便会删除该类,以防止对现有小部件进行重复和重新处理。
  • 在使用selectize之前,我使用了Select2,它具有相同的问题
  • 注释掉AJAX代码,我希望新的小部件具有标准的select输入。他们不。我不知道为什么会这样

那么,如何在不告诉用户在进行更改之前刷新/单击保存的情况下使selectize控件起作用?


这是一个事件委托问题。您将需要研究使用jQuerys .on()方法。这需要您将事件绑定到文档。但是,我现在不确定什么事件合适。最终,这是因为您的原始绑定代表了页面加载时DOM的初始版本,并且大多数情况下看不到通过ajax添加的新元素(小部件内容)。希望这会为您指明正确的方向,如果没有,我在工作时可以回答得更好。

这就是我所期望的,也是我添加该jQuery( document ).ajaxStop( function() {部件的原因,以便可以在新加载的小部件中初始化控件。但是,如果我删除了这一行,我希望新的小部件具有标准的HTML选择输入,但它们不会= s
Tom J Nowell

正如@ aaron-holbrook所说,通过使用widget-updatedand widget-added事件,它的方法是最干净的方法。我还要强调在@michaeljames代码中,元素id的使用#widgets-right。确保使用它来定位JS代码中的活动窗口小部件元素,否则您可能会得到重复的元素,因为您的代码还可能选择屏幕左侧的隐藏的非活动窗口小部件元素(添加窗口小部件时会被克隆)。
朱利安

Answers:


12

好消息,

我已经解决了。

很抱歉在我的初始评论中遗漏了要点,并为您提供了已经实施的答案。那会教我在火车上用手机接听!

您对ajaxstop的使用是正确的。大部分情况下,JS都无法正常工作,您可以看到正在初始化的CSS样式以及DOM中的更改。

问题实际上出在您的选择器上。

这是因为窗口小部件内容不是通过ajax加载的,实际上是从隐藏它的左侧列中克隆它,然后触发ajax调用以将窗口小部件的位置保存在右侧列中。这就解释了为什么ajaxstop可以工作,甚至克隆了思想内容。但是,由于左侧列中有小部件的隐藏版本,因此您的JS正在对此进行实例化。这样,当您将其拖动到右侧列时,就得到了隐藏的小部件的损坏副本。

因此,您需要在左侧选择一个。下面是更正的代码:

<script>
jQuery( document ).ready( function( $ ) {
    function runSelect() {
        var found = $( '#widgets-right select.testselectize' );
        found.each( function( index, value ) {

            $( value ).selectize();
                .removeClass( 'testselectize' )
                .addClass( 'run-' + window.counter );

            console.log( $val );
            window.counter++;
        } );
    }

    window.counter = 1;

    runSelect();

    $( document ).ajaxStop( function() {
        runSelect();
    } );
} );
</script>

天哪,我需要测试一下<3
Tom J Nowell

非常优雅的解决方案,可以解决重大的头痛问题!
bosco 2014年

3
我建议不要在每个“ ajaxStop”事件上运行,而建议在“ widget-added”和“ widget-updated”事件上使用。
蒂伦(Tyrun)2014年

16

正如@ aaron-holbrook所说,一种更清洁的方法是:

jQuery(document).on('widget-updated widget-added', function(){
    // your code to run
});

在许多情况下,您还需要在页面加载以及小部件更新时运行JS。您可以这样做。

function handle_widget_loading(){
   // your code to run
}
jQuery(document).ready( handle_widget_loading );
jQuery(document).on('widget-updated widget-added', handle_widget_loading );

只需粘贴此处以供参考,因为答案更容易找到该注释


2
可能应该使用jQuery而不是$
Mark Kaplun
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.