Как вызвать Drupal.attachBehaviors после успешного Ajax

10

У меня есть модуль, который обновляет узел через ajax при нажатии на ссылку.

Ссылка является переключателем, она должна обновлять узел со значением 1 при первом щелчке, затем со значением 0 при последующем щелчке и т. Д. Подобно включению / выключению чего-либо.

Приведенный ниже код работает при первом нажатии после загрузки страницы, но не при последующих щелчках. Я считаю, что Drupal.attachBehaviors должен вызываться / запускаться после каждого клика, но я не могу понять, как это сделать.

  1. Модуль

    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. Что я уже пробовал:

(a) Добавьте ajax_command_invoke(NULL, 'mymodule');к массиву $ ajax_commands вместе с $.fn.mymoduleфункцией

(б) Добавить $('body').ajaxSuccess(Drupal.attachBehaviors);в мой JavaScript. ajaxComplete пробовал также. Пробовал это и на документе.

(c) Создайте пользовательскую команду, как описано здесь http://www.jaypan.com/tutorial/calling-function-after-ajax-event-drupal-7

Примечание: я знаю, что это просто вопрос запуска attachBehaviors после каждого щелчка, чтобы «ajaxify» новый HTML-код был вставлен / изменен. Если я щёлкну по ссылке и наберу в консоли Drupal.attachBehaviors (), ссылка будет снова обработана моим javascript, о чем свидетельствует добавление класса 'middone', и ее можно будет щелкнуть снова.

Примечание. Также интересно, если я оставлю $ajax_commandsпустое значение и верну его (пустой массив) в конце функции обратного вызова, ссылка останется активной при первом и последующих щелчках. Он будет иметь ту функциональность, которую я ищу (переключатель). Однако, поскольку после каждого щелчка в html не вносятся никакие изменения, пользователь не может узнать, включен или выключен тумблер.

Любые указатели будут с благодарностью.

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

Частичный ответ:

Функция успеха Drupal ajax.js только повторно присоединяет поведение к формам (я думаю?)

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

поэтому я решил взломать функцию успеха всех моих объектов ajax.

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")) {

              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);

Функция успеха является копией вставки по умолчанию из ajax.js с добавленной строкой для повторного присоединения поведения. По какой-то причине Drupal.attachBehaviorsдолжно быть в пределах таймера. Я не могу просто получить его сам по причине, которую игнорирую.

Я оставлю этот вопрос открытым для немногих на тот случай, если кто-то сможет найти более элегантное решение и / или объяснить странность таймера.

Большое спасибо

JSL
источник
Почему вы хотите присоединить поведение снова и снова? они автоматически перезапускаются на любом новом элементе, созданном с использованием AJAX, так почему этого недостаточно?
Молот
поведение в моем случае автоматически не повторяется. THX
JSL

Ответы:

1

Может быть сложно прикрепить поведение ajax к контенту, который возвращается из самого запроса ajax. Однако это возможно.

Хотя ваш фрагмент кода hook_menu выглядит неполным, при условии, что он правильный (возвращает $ items, а функция закрыта) - В вашем случае вам может просто понадобиться настроить обратный вызов доставки на «ajax_deliver»

то есть:

/**
 * 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;

}
Дэвид Томас
источник
Спасибо за предложение, но это тоже не работает. Я использую ваш код в hook_menu и поведение не присоединяется автоматически.
JSL
1

После некоторой отладки я понял, что проблема не в моем коде.

Проблема заключалась в другом модуле, в моем случае в модуле colorbox, который был источником ошибки js в его собственной функции поведения. Я полагаю, что ошибка привела к остановке процесса прикрепленного поведения, и поэтому моя собственная функция поведения не была повторно присоединена. Ошибка видна в консоли.

Ошибка colorbox: в 7.24

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

и в 7.25

Uncaught TypeError: Cannot read property 'mobiledetect' of undefined

Моим решением было отключить модуль colorbox.

Большое спасибо всем, кто помог.

JSL
источник
1

Я не могу прокомментировать первый ответ , но вы можете установить свойство для colorbox в настройках. Например:

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'
});
Илья Кригузов
источник