Jak uruchomić Drupal.attachBehaviors po udanym Ajaxie

10

Mam moduł, który aktualizuje węzeł za pośrednictwem ajax po kliknięciu łącza.

Link jest przełącznikiem, powinien zaktualizować węzeł o wartości 1 przy pierwszym kliknięciu, a następnie o wartości 0 przy kolejnym kliknięciu itp. Jak włączanie / wyłączanie czegoś.

Poniższy kod działa przy pierwszym kliknięciu po załadowaniu strony, ale nie przy kolejnych kliknięciach. Uważam, że Drupal.attachBehaviors należy wywoływać / uruchamiać po każdym kliknięciu, ale nie mogę wymyślić, jak to zrobić.

  1. Moduł

    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. Co próbowałem do tej pory:

(a) Dodaj an ajax_command_invoke(NULL, 'mymodule');do tablicy $ ajax_commands w połączeniu z $.fn.mymodulefunkcją

(b) Dodaj $('body').ajaxSuccess(Drupal.attachBehaviors);do mojego javascript. ajaxComplete również próbował. Wypróbowałem to również w dokumencie.

(c) Utwórz niestandardowe polecenie, jak opisano tutaj http://www.jaypan.com/tutorial/calling-function-after-ajax-event-drupal-7

Uwaga: Wiem, że to tylko kwestia uruchomienia attachBehaviors po każdym kliknięciu, aby „ajaxify” nowy plik HTML został wstawiony / zmodyfikowany. Jeśli kliknę łącze, a następnie napiszę Drupal.attachBehaviors () w konsoli, łącze zostanie ponownie przetworzone przez mój skrypt javascript, o czym świadczy dodanie klasy „middone”, i można ponownie kliknąć.

Uwaga: Interesujące jest również to, że jeśli pozostawię $ajax_commandspuste i zwrócę je (pusta tablica) na końcu funkcji wywołania zwrotnego, link pozostanie klikalny przy pierwszym i kolejnych kliknięciach. Będzie miał funkcjonalność, której szukam (przełącznik). Ponieważ jednak po każdym kliknięciu html nie jest zmieniany, użytkownik nie może wiedzieć, czy przełącznik jest włączony, czy wyłączony.

Wszelkie wskazówki będą mile widziane.

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

Częściowa odpowiedź:

Funkcja sukcesu Drupal ajax.js ponownie dołącza zachowania tylko dla formularzy (myślę?)

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

więc postanowiłem zhakować wszystkie funkcje powodzenia moich obiektów ajax.

JavaScript staje się teraz

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

Funkcja sukcesu jest wklejaniem domyślnej kopii z ajax.js z dodaną linią do ponownego przyłączania zachowań. Z jakiegoś powodu Drupal.attachBehaviorsmusi być w czasie. Nie mogę mieć tego samego z powodu, który ignoruję.

Pozostawię to pytanie otwarte dla nielicznych, na wypadek, gdyby ktoś mógł znaleźć bardziej eleganckie rozwiązanie i / lub wyjaśnić dziwność timera.

Wielkie dzięki

JSL
źródło
Dlaczego chcesz ciągle przywiązywać zachowania? są one automatycznie uruchamiane ponownie na każdym nowym elemencie utworzonym za pomocą AJAX, więc dlaczego to nie wystarczy?
Mołot,
w moim przypadku zachowania nie są automatycznie przywracane. dzięki
JSL

Odpowiedzi:

1

Dołączanie zachowań ajax do treści zwracanych z samego żądania ajax może być trudne. Jest to jednak możliwe.

Chociaż fragment kodu hook_menu wygląda na niekompletny, przy założeniu, że jest poprawny (zwraca $ items i funkcja jest zamknięta) - W twoim przypadku może być konieczne dostosowanie wywołania zwrotnego dostawy do „ajax_deliver”

to znaczy:

/**
 * 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
źródło
Dzięki za sugestię, ale to też nie działa. Używam twojego kodu w hook_menu, a zachowania nie przywiązują się automatycznie.
JSL,
1

Po pewnym debugowaniu zdałem sobie sprawę, że problem nie dotyczy mojego kodu.

Problem dotyczył innego modułu, w moim przypadku modułu colorbox, który był źródłem błędu js w jego własnej funkcji zachowania. Uważam, że błąd spowodował zatrzymanie procesu dołączania zachowań i dlatego moja własna funkcja zachowań nie przywróciła się. Błąd można zobaczyć w konsoli.

Błąd colorbox: w 7.24

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

i w 7.25

Uncaught TypeError: Cannot read property 'mobiledetect' of undefined

Moim rozwiązaniem było wyłączenie modułu colorbox.

Dziękujemy wszystkim, którzy pomogli.

JSL
źródło
1

Nie mogę skomentować pierwszej odpowiedzi , ale możesz ustawić właściwość dla colorbox w ustawieniach. Na przykład:

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
źródło