So lösen Sie Drupal.attachBehaviors nach erfolgreichem Ajax aus

10

Ich habe ein Modul, das einen Knoten über Ajax aktualisiert, wenn auf einen Link geklickt wird.

Der Link ist ein Umschalter. Er sollte den Knoten beim ersten Klicken mit dem Wert 1 und beim nächsten Klicken mit dem Wert 0 aktualisieren. Zum Beispiel, wenn Sie etwas ein- oder ausschalten.

Der folgende Code funktioniert beim ersten Klicken nach dem Laden der Seite, jedoch nicht bei nachfolgenden Klicks. Ich glaube, Drupal.attachBehaviors muss nach jedem Klick aufgerufen / ausgelöst werden, aber ich kann nicht herausfinden, wie das geht.

  1. Das Modul

    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. Was ich bisher versucht habe:

(a) Fügen ajax_command_invoke(NULL, 'mymodule');Sie dem Array $ ajax_commands ein hinzu , das mit einer $.fn.mymoduleFunktion gekoppelt ist

(b) $('body').ajaxSuccess(Drupal.attachBehaviors);Zu meinem Javascript hinzufügen. ajaxComplete hat es ebenfalls versucht. Versuchte es auch auf dem Dokument.

(c) Erstellen Sie einen benutzerdefinierten Befehl, wie hier beschrieben. http://www.jaypan.com/tutorial/calling-function-after-ajax-event-drupal-7

Hinweis: Ich weiß, dass es nur darum geht, attachBehaviors nach jedem Klick auszulösen, um das neue HTML, das eingefügt / geändert wird, zu "ajaxifizieren". Wenn ich auf den Link klicke und dann Drupal.attachBehaviors () in die Konsole eingebe, wird der Link von meinem Javascript erneut verarbeitet, was durch das Hinzufügen der Klasse 'middone' belegt wird, und kann erneut angeklickt werden.

Hinweis: Interessant ist auch, dass $ajax_commandsder Link beim ersten und den folgenden Klicks anklickbar bleibt , wenn ich das Feld leer lasse und es (leeres Array) am Ende der Rückruffunktion zurückgebe. Es wird die Funktionalität haben, die ich suche (ein Umschalter). Da jedoch nach jedem Klick keine Änderungen am HTML vorgenommen werden, kann der Benutzer nicht feststellen, ob der Schalter ein- oder ausgeschaltet ist.

Alle Hinweise wäre sehr dankbar.

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

Eine teilweise Antwort:

Die Erfolgsfunktion von Drupal ajax.j fügt nur Verhaltensweisen für Formulare wieder hinzu (glaube ich?)

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

Deshalb habe ich beschlossen, alle Erfolgsfunktionen meiner Ajax-Objekte zu hacken.

Das Javascript wird jetzt

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

Die Erfolgsfunktion ist ein Kopieren und Einfügen der Standardeinstellung aus ajax.js mit einer zusätzlichen Zeile für das erneute Anhängen von Verhalten. Aus irgendeinem Grund Drupal.attachBehaviorsmuss innerhalb eines Timers sein. Ich kann es aus einem Grund, den ich ignoriere, nicht einfach alleine haben.

Ich werde diese Frage für einige offen lassen, falls jemand entweder eine elegantere Lösung finden und / oder die Seltsamkeit des Timers erklären kann.

Danke vielmals

JSL
quelle
Warum sollten Sie immer wieder Verhaltensweisen hinzufügen wollen? Sie werden automatisch für jedes neue Element ausgeführt, das mit AJAX erstellt wurde. Warum reicht das nicht aus?
Mołot
Verhaltensweisen werden in meinem Fall nicht automatisch neu definiert. thx
JSL

Antworten:

1

Es kann schwierig sein, Ajax-Verhalten an Inhalte anzuhängen, die von einer Ajax-Anforderung selbst zurückgegeben werden. Es ist jedoch möglich.

Obwohl Ihr Hook_menu-Code-Snippet unvollständig aussieht, vorausgesetzt, es ist korrekt (gibt $ items zurück und die Funktion ist geschlossen) - In Ihrem Fall müssen Sie möglicherweise nur den Rückruf für die Zustellung auf 'ajax_deliver' anpassen.

dh:

/**
 * 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
quelle
Danke für den Vorschlag, aber das funktioniert auch nicht. Ich verwende Ihren Code in hook_menu und Verhaltensweisen werden nicht automatisch neu angehängt.
JSL
1

Nach einigem Debuggen wurde mir klar, dass das Problem nicht mit meinem Code zusammenhängt.

Das Problem lag bei einem anderen Modul, in meinem Fall dem Colorbox-Modul, das die Ursache für einen js-Fehler in seiner eigenen Verhaltensfunktion war. Ich glaube, der Fehler hat dazu geführt, dass der Prozess zum Anhängen von Verhaltensweisen angehalten wurde, und daher wurde meine eigene Verhaltensfunktion nicht erneut angehängt. Der Fehler wurde in der Konsole angezeigt.

Der Colorbox-Fehler: in 7.24

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

und in 7.25

Uncaught TypeError: Cannot read property 'mobiledetect' of undefined

Meine Lösung bestand darin, das Colorbox-Modul zu deaktivieren.

Vielen Dank an alle, die geholfen haben.

JSL
quelle
1

Ich kann die erste Antwort nicht kommentieren , aber Sie können die Eigenschaft für das Farbfeld in den Einstellungen festlegen. Zum Beispiel:

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
quelle