Executando Javascript quando um widget é adicionado no back-end

20

Eu tenho widgets que possuem controles javascript anexados a eles.

Se o widget estiver presente quando a página de administração do widget for carregada, os controles funcionarão corretamente.

Quando adiciono um novo widget, eles não funcionam corretamente, recebo a marcação, mas nenhum evento javascript entra em vigor.

Se eu salvar o novo widget, quando o formulário for recarregado, os controles serão criados corretamente e agora funcionarão.

A atualização da página também corrige o problema, mas apenas para os widgets existentes. Novos widgets ainda têm esse problema.

Especificamente, estou executando o selectize nas entradas selecionadas nesses pontos:

  • documento pronto
  • Ajaxcomplete

Eu verifiquei que meu código é executado em cada evento, conforme desejado, mas os resultados não são os esperados.

Aqui está um plug-in de teste que demonstra o problema:

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

Você verá que tenho um contador que aumenta a cada elemento selecionado que ele pode converter.

Notas:

  • Quando a página do widget é carregada, vejo o contador aumentando no console JS conforme o esperado
  • Quando adiciono um novo widget, o código é executado, no entanto, ele não encontra nenhum elemento selecionado, como demonstrado por found.length sendo 0. Esse não deve ser o caso, pois todo novo widget desse tipo deve tem um elemento select
  • Os elementos select possuem uma classe para identificá-los. Essa classe é removida quando a biblioteca selectize é aplicada para impedir a duplicação e o reprocessamento nos widgets existentes.
  • Antes de usar o selectize, usei o Select2, que tinha o mesmo problema
  • Comentando o código AJAX, eu esperaria que novos widgets tivessem uma entrada de seleção padrão. Eles não. Não sei por que esse é o caso

Então, como faço para que o controle de seleção funcione sem solicitar ao usuário que atualize / clique em salvar antes de fazer alterações?

Tom J Nowell
fonte
É um problema de delegação de eventos. Você precisará examinar o .on()método jQuerys . O que requer que você vincule um evento ao documento. No entanto, qual evento será apropriado, não tenho certeza no momento. Por fim, é porque suas ligações originais representam a versão inicial do DOM quando a página foi carregada e, na maioria das vezes, são cegos para os novos elementos (conteúdo do widget) que estão sendo adicionados via ajax. Espero que isso aponte a direção certa; se não, posso responder melhor quando estiver no trabalho.
Era o que eu esperava e por que adicionei a jQuery( document ).ajaxStop( function() {peça para poder inicializar os controles nos widgets recém-carregados. No entanto, se eu removesse essa linha, esperaria que novos widgets tivessem entradas de seleção HTML padrão, mas eles não = s
Tom J Nowell
Como @ aaron-holbrook comentou, sua abordagem é a mais limpa usando os eventos widget-updatede widget-added. Também quero enfatizar, no código @michaeljames, o uso do ID do elemento #widgets-right. Certifique-se de usá-lo para direcionar elementos de widgets ativos em seu código JS, caso contrário, você poderá obter elementos duplicados, pois seu código também pode selecionar elementos de widget inativos ocultos no lado esquerdo da tela (e aqueles clonados quando o widget é adicionado).
Julien

Respostas:

12

Boas notícias,

Eu consertei isso.

Desculpas por perder sua essência no meu comentário inicial e dar uma resposta que você já havia implementado. Isso me ensinará a atender no meu telefone enquanto estiver em um trem!

Seu uso do ajaxstop está correto. Inferno, a maior parte do JS está funcionando corretamente, você pode ver os estilos css sendo inicializados e as alterações no DOM.

O problema está de fato com o seu seletor.

Isso ocorre porque o conteúdo do widget não é carregado via ajax, na verdade, ele é clonado da coluna da esquerda, onde está oculto, e então dispara uma chamada ajax para salvar a posição do widget na coluna da direita. Isso explica por que o ajaxstop funciona bem, mesmo que o conteúdo seja clonado. No entanto, como há uma versão oculta do widget na coluna da esquerda, seu JS está instanciando isso. Assim, quando você o arrasta para a coluna da direita, você está obtendo um clone mutilado do widget oculto.

Portanto, você precisa selecionar o lado esquerdo. Abaixo está o código corrigido:

<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>
kaiser
fonte
Santo Moly, eu preciso fazer o teste <3
Tom J Nowell
Solução muito elegante para uma grande dor de cabeça!
bosco
3
Eu desaconselharia a execução em todos os eventos 'ajaxStop' e, em vez disso, sugeriria o uso de eventos 'widget-added' e 'widget-updated'.
Tyrun 11/08/14
16

Como @ aaron-holbrook comentou, uma abordagem mais limpa será:

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

Em muitos casos, você também desejará executar o JS quando a página carregar, bem como quando os widgets forem atualizados. Você pode fazer assim.

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

Basta colar aqui para referência, pois as respostas são muito mais fáceis de encontrar que os comentários

chifliiiii
fonte
2
provavelmente deve usar jQuery em vez de $
Mark Kaplun