Come attivare Drupal.attachBehaviors dopo l'Ajax riuscito


10

Ho un modulo che aggiorna un nodo tramite Ajax quando si fa clic su un collegamento.

Il collegamento è un interruttore, dovrebbe aggiornare il nodo con il valore 1 al primo clic, quindi con il valore 0 a un clic successivo, ecc. Come accendere / spegnere qualcosa.

Il codice seguente funziona al primo clic dopo il caricamento della pagina, ma non ai clic successivi. Credo che Drupal.attachBehaviors debba essere chiamato / attivato dopo ogni clic, ma non riesco a capire come farlo.

  1. Il modulo

    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. Quello che ho provato finora:

(a) Aggiungi un ajax_command_invoke(NULL, 'mymodule');array di $ ajax_commands accoppiato con una $.fn.mymodulefunzione

(b) Aggiungi $('body').ajaxSuccess(Drupal.attachBehaviors);al mio javascript. ajaxComplete anche provato. Ho provato anche sul documento.

(c) Crea un comando personalizzato come dettagliato qui http://www.jaypan.com/tutorial/calling-function-after-ajax-event-drupal-7

Nota: so che è solo una questione di innescare attachBehaviors dopo ogni clic per "ajaxify" il nuovo codice HTML da inserire / modificare. Se faccio clic sul collegamento e digito Drupal.attachBehaviors () nella console, il collegamento verrà nuovamente elaborato dal mio javascript, come evidenziato dall'aggiunta della classe 'middone', e può essere nuovamente cliccato.

Nota: anche di interesse, se lascio il $ajax_commandsvuoto e lo restituisco (array vuoto) alla fine della funzione di callback, il collegamento rimarrà cliccabile sul primo e sui successivi clic. Avrà la funzionalità che sto cercando (un interruttore). Tuttavia, poiché non viene apportata alcuna modifica all'html dopo ogni clic, l'utente non può sapere se l'interruttore è attivato o disattivato.

Qualsiasi suggerimento sarebbe molto apprezzato.

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

Una risposta parziale:

La funzione di successo drupal ajax.js ricollega i comportamenti solo per i moduli (penso?)

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

così ho deciso di hackerare la funzione di successo di tutti i miei oggetti ajax.

Il Javascript ora diventa

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

La funzione di successo è una copia incolla del valore predefinito da ajax.js con una riga aggiunta per ricollegare i comportamenti. Per qualche motivo, Drupal.attachBehaviorsdeve essere all'interno di un timer. Non posso averlo da solo per un motivo che ignoro.

Lascerò questa domanda aperta per pochi nel caso in cui qualcuno possa trovare una soluzione più elegante e / o spiegare la stranezza del timer.

Grazie molto


Perché dovresti voler associare comportamenti ancora e ancora? vengono automaticamente rieseguiti su qualsiasi nuovo elemento creato utilizzando AJAX, quindi perché non è abbastanza?
Mołot,

i comportamenti non vengono automaticamente riapplicati nel mio caso. grazie
JSL il

Risposte:


1

Può essere complicato associare comportamenti ajax a contenuti restituiti da una stessa richiesta ajax. Tuttavia, è possibile.

Anche se lo snippet di codice hook_menu sembra incompleto, supponendo che sia corretto (restituisce $ articoli e la funzione è chiusa) - Nel tuo caso, potrebbe essere necessario regolare il callback di consegna su 'ajax_deliver'

vale a dire:

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

}

Grazie per il suggerimento ma neanche questo funziona. Uso il tuo codice in hook_menu e i comportamenti non si ricollegano automaticamente.
JSL

1

Dopo un po 'di debug, mi sono reso conto che il problema non riguardava il mio codice.

Il problema risiedeva in un altro modulo, nel mio caso il modulo colorbox, che era la fonte di un errore js nella sua funzione comportamentale. Credo che l'errore abbia causato l'arresto del processo di comportamento degli allegati e, come tale, la mia funzione di comportamenti non si è ricollegata. L'errore potrebbe essere visualizzato nella console.

L'errore colorbox: in 7.24

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

e in 7.25

Uncaught TypeError: Cannot read property 'mobiledetect' of undefined

La mia soluzione era disabilitare il modulo colorbox.

Mille grazie a tutti coloro che hanno aiutato.


1

Non posso commentare la prima risposta , ma puoi impostare la proprietà per colorbox nelle impostazioni. Per esempio:

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'
});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.