web-dev-qa-db-fra.com

Comment déclencher Drupal.attachBehaviors après un Ajax réussi

J'ai un module qui met à jour un nœud via ajax lorsqu'un lien est cliqué.

Le lien est une bascule, il doit mettre à jour le nœud avec la valeur 1 au premier clic, puis avec la valeur 0 au clic suivant, etc. Comme activer/désactiver quelque chose.

Le code ci-dessous fonctionne sur le premier clic après le chargement de la page, mais pas sur les clics suivants. Je crois que Drupal.attachBehaviors doit être appelé/déclenché après chaque clic, mais je ne sais pas comment faire cela.

  1. Le module

    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. Ce que j'ai essayé jusqu'à présent:

(a) Ajoutez une ajax_command_invoke(NULL, 'mymodule'); au tableau $ ajax_commands couplée à une fonction $.fn.mymodule

(b) Ajoutez $('body').ajaxSuccess(Drupal.attachBehaviors); à mon javascript. ajaxComplete a également essayé. J'ai également essayé sur le document.

(c) Créez une commande personnalisée comme détaillé ici http://www.jaypan.com/tutorial/calling-function-after-ajax-event-drupal-7

Remarque: je sais qu'il s'agit simplement de déclencher attachBehaviors après chaque clic pour "ajaxify" le nouveau html inséré/modifié. Si je clique sur le lien et que je tape Drupal.attachBehaviors () dans la console, le lien sera à nouveau traité par mon javascript, comme en témoigne l'ajout de la classe 'middone', et peut être cliqué à nouveau.

Remarque: Également intéressant, si je laisse le $ajax_commands Vide et le renvoie (tableau vide) à la fin de la fonction de rappel, le lien restera cliquable lors du premier clic et des clics suivants. Il aura les fonctionnalités que je recherche (une bascule). Cependant, étant donné qu'aucune modification n'est apportée au code HTML après chaque clic, l'utilisateur n'a aucun moyen de savoir si la bascule est activée ou désactivée.

Tout pointeur serait grandement apprécié.

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

Une réponse partielle:

La fonction de succès Drupal ajax.js ne fait que rattacher les comportements aux formulaires (je pense?)

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

j'ai donc décidé de pirater la fonction de réussite de tous mes objets ajax.

Le Javascript devient maintenant

    (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 fonction de réussite est un copier-coller de la valeur par défaut d'ajax.js avec une ligne ajoutée pour les comportements de rattachement. Pour une raison quelconque, Drupal.attachBehaviors Doit se trouver dans une minuterie. Je ne peux pas l'avoir tout seul pour une raison que j'ignore.

Je laisserai cette question ouverte à quelques-uns au cas où quelqu'un pourrait trouver une solution plus élégante et/ou expliquer la bizarrerie du minuteur.

Merci beaucoup

10
JSL

Après quelques débogages, j'ai réalisé que le problème n'était pas lié à mon code.

Le problème résidait dans un autre module, dans mon cas le module colorbox, qui était à l'origine d'une erreur js dans sa propre fonction de comportement. Je crois que l'erreur a entraîné l'arrêt du processus d'attachement des comportements et, en tant que tel, ma propre fonction de comportement n'a pas été réattachée. L'erreur a pu être vue dans la console.

L'erreur colorbox: en 7.24

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

et en 7.25

Uncaught TypeError: Cannot read property 'mobiledetect' of undefined

Ma solution était de désactiver le module colorbox.

Un grand merci à tous ceux qui ont aidé.

1
JSL

Je ne peux pas commenter première réponse , mais vous pouvez définir la propriété de colorbox dans les paramètres. Par exemple:

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'
});
1
Ilya Krigouzov

Il peut être difficile d'attacher des comportements ajax au contenu renvoyé par une demande ajax elle-même. Mais c'est possible.

Bien que votre extrait de code hook_menu semble incomplet, en supposant qu'il est correct (retourne $ items et la fonction est fermée) - Dans votre cas, vous devrez peut-être simplement ajuster le rappel de livraison à 'ajax_deliver'

c'est à 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;

}
1
David Thomas