Como disparar Drupal.attachBehaviors após o Ajax bem-sucedido

10

Eu tenho um módulo que atualiza um nó via ajax quando um link é clicado.

O link é uma alternância, ele deve atualizar o nó com o valor 1 no primeiro clique e, em seguida, com o valor 0 no clique subsequente, etc. Como ativar / desativar algo.

O código abaixo funciona no primeiro clique após o carregamento da página, mas não nos cliques subsequentes. Acredito que Drupal.attachBehaviors deve ser chamado / acionado após cada clique, mas não consigo descobrir como fazer isso.

  1. O Módulo

    function mymodule_menu() {
      $items['mypath/%/%/ajax'] = array(
      'title' => 'My title',
      'page callback' => 'mymodule_ajax_callback',
      'page arguments' => array(1,2),
      'access arguments' => array('access content'),
      'type' => MENU_CALLBACK,
      );
    
      ...
    }
    
    function mymodule_ajax_callback($id, $status) {
      //Validation[...]
    
      //Node Update using $id as the nid and $status as the field value[...]
    
      // Define a new array to hold our AJAX commands.
      $ajax_commands = array();
    
      // Create a new AJAX command that replaces the #div.
      $replacedivid = '#status'.$id;
      $replacestring = '<div id="status'.$id.'"><a data-url="'.base_path().'mypath/'.$id.'/'.$new_status.'/ajax" title="This item is marked as '.$status_text.'" id="statuslink'.$id.'" class="midui">'.$status_text.'</a></div>';
    
    
      $ajax_commands[] = ajax_command_replace($replacedivid, $replacestring);
    
    
      return drupal_json_output($ajax_commands);
    }
    
  2. Javascript

    (function ($) {
      Drupal.behaviors.mymodule = {
        attach: function(context, settings) {
          var $uilink = $('.midui'); //find all links
    
          for (var i=0;i<$uilink.length;i++) { //Loop
            var $link = $('#' + $uilink[i].id);
            if (!$link.hasClass("middone")) {
    
              new Drupal.ajax('#' + $uilink[i].id, $link, {
                url: $link.attr('data-url'),
                effect: 'fade',
                settings: {},
                progress: {
                  type: 'throbber'
                },
                event: 'click tap'
              });
    
              $link.addClass("middone"); //add class when we're done
    
            }
          }
        }
      }
    })(jQuery);
    
  3. O que eu tentei até agora:

(a) Adicione um ajax_command_invoke(NULL, 'mymodule');ao array $ ajax_commands juntamente com uma $.fn.mymodulefunção

(b) Adicione $('body').ajaxSuccess(Drupal.attachBehaviors);ao meu javascript. o ajaxComplete tentou também. Tentei no documento também.

(c) Crie um comando personalizado conforme detalhado aqui http://www.jaypan.com/tutorial/calling-function-after-ajax-event-drupal-7

Nota: Eu sei que é apenas uma questão de acionar o attachBehaviors após cada clique para 'ajaxify' o novo html sendo inserido / modificado. Se eu clicar no link e digitar Drupal.attachBehaviors () no console, o link será processado novamente pelo meu javascript, conforme evidenciado pela adição da classe 'middone', e poderá ser clicado novamente.

Nota: Também é interessante que, se eu deixar a caixa $ajax_commandsvazia e a retornar (matriz vazia) no final da função de retorno de chamada, o link permanecerá clicável nos primeiros e subsequentes cliques. Ele terá a funcionalidade que estou procurando (uma alternância). No entanto, como nenhuma alteração é feita no html após cada clique, não há como o usuário saber se a alternância está ativada ou desativada.

Qualquer ponteiro seria muito apreciado.

==================================================== =====

Resposta parcial:

A função de sucesso Drupal ajax.js reaparece apenas comportamentos para formulários (eu acho?)

    if (this.form) {
      var settings = this.settings || Drupal.settings;
      Drupal.attachBehaviors(this.form, settings);
    }

então decidi hackear a função de sucesso de todos os meus objetos ajax.

O Javascript agora se torna

    (function ($) {
      Drupal.behaviors.mymodule = {
        attach: function(context, settings) {
          var $uilink = $('.midui'); //find all links

          for (var i=0;i<$uilink.length;i++) { //Loop
            var $link = $('#' + $uilink[i].id);
            if (!$link.hasClass("middone")) {

              myAjax = new Drupal.ajax('#' + $uilink[i].id, $link, {
                url: $link.attr('data-url'),
                effect: 'fade',
                settings: {},
                progress: {
                  type: 'throbber'
                },
                event: 'click tap'
              });

              myAjax.options.success = function (response, status) {
                //Trigger Attach Behaviors
                setTimeout(function(){Drupal.attachBehaviors($(myAjax.selector))}, 0);
                // Sanity check for browser support (object expected).
                // When using iFrame uploads, responses must be returned as a string.
                if (typeof response == 'string') {
                  response = $.parseJSON(response);
                }

                return myAjax.success(response, status);
              }

              $link.addClass("middone"); //add class when we're done

            }
          }
        }
      }
    })(jQuery);

A função success é uma pasta de cópia do padrão do ajax.js com uma linha adicionada para reconectar comportamentos. Por alguma razão, Drupal.attachBehaviorsdeve estar dentro de um temporizador. Não posso simplesmente tê-lo por um motivo que ignoro.

Deixarei esta pergunta em aberto para poucos, caso alguém encontre uma solução mais elegante e / ou explique a singularidade do temporizador.

Muito Obrigado

JSL
fonte
Por que você gostaria de anexar comportamentos repetidamente? eles são reexecutados automaticamente em qualquer novo elemento criado usando o AJAX. Por que não basta?
Mołot
comportamentos não são reativados automaticamente no meu caso. thx
JSL

Respostas:

1

Pode ser complicado anexar comportamentos de ajax ao conteúdo retornado de uma solicitação de ajax. No entanto, é possível.

Embora seu snippet de código hook_menu pareça incompleto, supondo que esteja correto (retorna $ itens e a função está fechada) - No seu caso, pode ser necessário ajustar o retorno de chamada de entrega para 'ajax_deliver'

ou seja:

/**
 * Implements hook_menu
 */
function mymodule_menu() {

  $items['mypath/%/%/ajax'] = array(
    'title' => 'My title',
    'page callback' => 'mymodule_ajax_callback',
    'page arguments' => array(1,2),
    'access arguments' => array('access content'),
    'delivery callback' => 'ajax_deliver',
    'theme callback' => 'ajax_base_page_theme',
    'type' => MENU_CALLBACK,
  );

  return $items;

}
David Thomas
fonte
Obrigado pela sugestão, mas isso também não funciona. Eu uso seu código no hook_menu e os comportamentos não são reconectados automaticamente.
JSL 12/12
1

Após alguma depuração, percebi que o problema não estava no meu código.

O problema estava em outro módulo, no meu caso, o módulo colorbox, que foi a fonte de um erro js em sua própria função de comportamentos. Acredito que o erro interrompeu o processo de anexar comportamentos e, como tal, minha função de comportamentos não foi anexada novamente. O erro pode ser visto no console.

O erro da caixa de cores: na versão 7.24

Uncaught TypeError: Cannot read property 'transition' of undefined colorbox_inline.js?

e em 7,25

Uncaught TypeError: Cannot read property 'mobiledetect' of undefined

Minha solução foi desativar o módulo colorbox.

Muito obrigado a todos que ajudaram.

JSL
fonte
1

Não posso comentar a primeira resposta , mas você pode definir a propriedade para o colorbox nas configurações. Por exemplo:

myAjax = new Drupal.ajax('#' + $uilink[i].id, $link, {
  url: $link.attr('data-url'),
  effect: 'fade',
  settings: {
    colorbox: {
      mobiledetect: false
    }
  },
  progress: {
    type: 'throbber'
  },
  event: 'click tap'
});
Ilya Krigouzov
fonte