Comment ajouter une fenêtre de confirmation JS en cliquant sur un bouton #ajax

10

J'ai une entrée de bouton FAPI de base qui est activée #ajax et qui fonctionne bien, mais je veux ajouter un JS "Êtes-vous sûr?" une fenêtre de confirmation lorsque vous cliquez sur le bouton avant que le code ne s'exécute réellement, et je ne sais pas comment le faire parce que le JS de FAPI semble manger le clic avant que je puisse y arriver, peu importe ce que je fais.

J'ai essayé d'ajouter un gestionnaire onclick en ligne, comme ceci:

$form['search_filters']['channels']['channel_delete_' . $channel->nid] = array(
  '#type' => 'button',
  '#name' => 'channel_delete_' . $channel->nid,
  '#value' => 'Delete',
  '#attributes' => array(
    'class' => array('confirm'),
    'onclick' => "return confirm('Are you sure you want to delete that?')"
  ),
  '#button_type' => 'no-submit',
  '#ajax' => array(
    'callback' => 'delete_channel_callback',
    'wrapper' => 'channel_container_' . $channel->nid
  ),
);

... ce qui n'aide pas, et j'ai également essayé d'ajouter:

$('.confirm').click(function(e) {
  e.preventDefault();
  alert('Is this recognized')? // never runs
});

dans le JS de mon module qui est également ignoré.

D'autres idées? Existe-t-il un moyen d'ajouter un gestionnaire de soumission en haut de la pile que Drupal #ajax reconnaîtra?

Mike Crittenden
la source

Réponses:

15

Drupal est un framework PHP, et il est étonnant de voir combien de choses fantastiques AJAX vous pouvez obtenir en utilisant cela et le FAPI. Mais il a ses limites et pour un cas d'utilisation comme celui-ci, je vous suggère d'utiliser du JavaScript personnalisé. De plus, au lieu d'utiliser la boîte de dialogue généralement JavaScript, vous pouvez utiliser l'interface jQuery pour créer une boîte de dialogue thématique à la place.

Quoi qu'il en soit, le problème auquel vous êtes confronté est probablement dû au fait que vous utilisez AJAX sur le bouton d'envoi. Étant donné que vous utilisez AJAX pour l'appel de suppression réel, preventDefaultetc. ne fonctionnera pas.

Ce que vous auriez à faire, c'est quelque chose comme ça. (Ceci n'est pas largement testé mais devrait fonctionner.)

Drupal.behaviors.module = {
  attach: function() {

    var events = $('.confirm').data('events'); // Get the jQuery events.
    $('.confirm').unbind('click'); // Remove the click events.
    $('.confirm').click(function () {
      if (confirm('Are you sure you want to delete that?')) {
        $.each(events.click, function() {
          this.handler(); // Invoke the click handlers that was removed.
        });
      }
      // Prevent default action.
      return false;
    });
  }
}
googletorp
la source
J'ai également ajouté $ ('. Confirm'). Unbind ('mousedown'); Drupal écoute également l'événement 'mousedown'.
milkovsky
cela ne brisera-t-il pas le bouton si l'utilisateur annule la boîte de dialogue de confirmation puis clique à nouveau? (parce que $('.confirm').unbind('click');) ... ou ai-je mal lu? désolé pas familier avecunbind
ErichBSchulz
1
@ErichBSchulz Unbind n'est appelé qu'une seule fois, par la méthode attach qui est appelée au chargement de la page.
googletorp
gist.github.com/guoxiangke/0dffa7722a67f052c7ce TypeError non capturé: impossible de lire la propriété «clic» de la propriété non définie ?????? J'ai un formulaire, dans node / add / content-type, et je l'ajax, utilisez js validate
bluesky_still
4

confirmant que Jeroen corrige le code de googletorp.

Cependant, j'ai moi-même découvert que les égalités de type "mousedown" doivent être débidées et reliées à nouveau. Donc, le morceau de code qui a fonctionné pour moi est le suivant:

(function ($) {
  Drupal.behaviors.confirm = {
    attach: function(context, settings) {
      var events =  $('.form-submit-delete').clone(true).data('events');// Get the jQuery events.
      $('.form-submit-delete').unbind('mousedown'); // Remove the click events.
      $('.form-submit-delete').mousedown(function () {
    if (confirm('Are you sure you want to delete that?')) {
      $.each(events.mousedown, function() {
        this.handler(); // Invoke the mousedown handlers that was removed.
      });
    }
    // Prevent default action.
    return false;
      });
    }
  }
})(jQuery);
Turtletrail
la source
C'est vraiment un gaspillage de ressources pour cloner des objets DOM à moins que vous n'en ayez réellement besoin.
googletorp
Salut, j'ai rencontré la même question, tout va bien, mais j'ai rencontré une erreur js: "TypeError Uncaught: Impossible de lire la propriété 'click' de indéfini" également pour "mousedown".
bluesky_still
C'est la seule solution que j'ai pu mettre au travail. Le clonage est la clé ici. Sans le clone, lorsque vous cliquez sur OK, l'alerte réapparaît instantanément.
Felix Eve
4

La question est ancienne, mais je m'y intéressais aussi. À mon avis, le moyen le plus simple consiste à utiliser l'événement click dans votre définition Ajax, car Drupal utilise l'événement mousedown par défaut:

$form['submit'] = array(
  '#type' => 'submit',
  '#value' => t('some value'),
  '#attributes' => array(
    'class' => array('some-class'),
    ),
  '#ajax' => array(
    'event' => 'click',    //add this line!
    'callback' => 'some_callback',
    'wrapper' => 'some-wrapper',
  ),
);

Ensuite, il vous suffit d'ajouter un .mousedown()événement à votre bouton dans votre fichier Javascript, car il est déclenché avant l'événement click:

$('.some-class').mousedown(function() {
  //do something
});

Si vous souhaitez toujours que votre demande Ajax soit appelée avec l'événement mousedown, vous pouvez utiliser un événement personnalisé:

//change this line in the Ajax Defintion of your button
'event' => 'click',
//to
'event' => 'custom_event',

Ensuite, vous pouvez déclencher cet événement dans le .mousedown()cas de votre fichier Javascript:

$('.some-class').mousedown(function() {
  //do something
  $('.some-class').trigger('custom_event');
});

Les deux versions fonctionnent!

Daniel
la source
Ouais! J'aime celui-ci car il fait ce que vous voulez: vous donne une idée du processus standard de Drupal que vous pouvez ensuite appeler lorsque vous en avez besoin. Nb. J'avais besoin d'avoir un preventDefaultdans mon gestionnaire de clics pour empêcher la soumission normale (non-js) du formulaire, encore.
artfulrobot
0

Avez-vous essayé d'exécuter votre JS dans un comportement Drupal? Il se peut que votre gestionnaire de clics soit attaché après celui de Drupal.

Quoi qu'il en soit, vous devriez pouvoir dissocier le gestionnaire de clics de Drupal sur le bouton afin que vous soyez appelé en premier et vous pouvez appeler le gestionnaire de clics Ajax de Drupal manuellement (et conditionnellement).

Adam DiCarlo
la source
0

Répondre à noter que le code de googletorp n'est pas correct à 100%.

Vous devez changer la ligne où les événements sont stockés en ceci:

var events = $('.confirm').clone(true).data('events'); // Get the jQuery events.

De cette façon, vous éliminez tous les problèmes de référence d'objet, donc lors de la dissociation des événements de clic, cela ne se dissocie pas également dans votre var;)

Sachez également que depuis jQuery 1.8, la méthode .data () est obsolète. L'obtention des données d'événements se fait désormais via une structure de données interne:

.data («événements») : jQuery stocke ses données liées aux événements dans un objet de données nommé (attendez-le) événements sur chaque élément. Il s'agit d'une structure de données interne, donc dans la version 1.8, elle sera supprimée de l'espace de nom des données utilisateur afin de ne pas entrer en conflit avec les éléments du même nom. Les données d'événement de jQuery sont toujours accessibles via jQuery._data (élément, "events") mais sachez qu'il s'agit d'une structure de données interne non documentée et qui ne doit pas être modifiée.

Source: http://blog.jquery.com/2011/11/08/08/building-a-slimmer-jquery/

Jeroen
la source
0

J'ai trouvé de nombreuses réponses utiles ci-dessus et j'ai réussi à faire fonctionner mon formulaire. Dans l'ensemble, voici ce qui a fonctionné pour mon application: un bouton de suppression de formulaire avec une boîte de dialogue de confirmation et un rappel AJAX pour modifier le contenu d'une liste de sélection.

Le javascript:

$form['my_form']['delete_button_js'] = array(
  '#markup' => '<script type="text/javascript">
  (function ($) {
     // override the default confirmation dialog behavior
     Drupal.behaviors.confirm = { 

      // Get the jQuery events.
      attach: function(context, settings) {
      var events =  $(\'.deleteButtonClass\').clone(true).data(\'events\'); 

      $(\'.deleteButtonClass\').unbind(\'mousedown\'); // Remove the mousedown event.

      $(\'.deleteButtonClass\').mousedown(function () { 
           // Popup the confirmation
           if (confirm(\'Are you sure you want to delete the Group?\')) {
             // if YES, then we fire the AJAX event 
             $(\'.deleteButtonClass\').trigger(\'deleteGroupEvent\'); 
           }
           // Override the default action.
           return false;
        });
    }
            }
  })(jQuery);
  </script>
  ',
);

L'élément de formulaire (liste de sélection) à modifier:

$form['my_form']['select_list'] = array(
         '#type' => 'select',
         '#title' => t('My Title'),
         '#options' =>  $optionsArray,
         '#size' => 5,
         '#prefix' => t('<div id="mySelectList">'),
         '#suffix' => t('</div>'),
    }

Le bouton:

$form['my_form']['delete_button'] = array(
  '#type' => 'button',
  '#value' => 'Delete',

  '#attributes' => array( 
      'class' => array('deleteButtonClass'), 
    ),

  '#ajax' => array (

    // this is the custom event that will be fired from the jQuery function
    'event' => 'deleteGroupEvent', 

    'callback' => 'ajax_delete_callback',
    'wrapper' => 'mySelectList',
    ),

);

Et enfin, le rappel AJAX:

function ajax_delete_callback ($form, $form_state) {

  // callback implementation code

  return $form['my_form']['select_list'];
}
Susanne
la source
-1

J'ai corrigé cela en modifiant le fichier drupal misc / ajax.jx.

Créez une copie du fichier ajax.js et mettez-le dans n'importe quel module personnalisé et Drupal.ajax = function (base, element, element_settings) { modifiez la fonction dans beforeSend:

beforeSend: function (xmlhttprequest, options) {

    if( ajax.url =='/?q=field_collection/ajax'){ // condition for when click on the Remove button
      if (confirm('Are you sure you want to remove this?')) {
       ajax.ajaxing = true;
       return ajax.beforeSend(xmlhttprequest, options);
      }
      xmlhttprequest.abort();
    } else{
        ajax.ajaxing = true;
        return ajax.beforeSend(`xmlhttprequest`, options);   
     }    
},

Cela fonctionne bien pour moi.

Hemant
la source
1
Il compte comme un noyau de piratage et devrait probablement être évité.
Mołot
1
Et est complètement inutile - fr.wikipedia.org/wiki/Monkey_patch
Clive
C'était la seule façon de faire fonctionner ce concept sans montrer de doubles cases de confirmation. La seule exception est que j'ai dû faire l'instruction if vérifier si ajax.url == 'field_collection_remove_js'. Peut-être que c'est à cause de la version de Drupal que j'utilise?
Richard
-1

Peut-être un peu vieux, mais je me demande pourquoi nous ne pouvons pas simplement utiliser:

(function($, Drupal, window, document, undefined) {

Drupal.behaviors.oc_ua_pc = {
  attach: function(context, settings) {
    $('#button').click(function () {
      if(confirm('This action cannot be undone and you cannot change the form later. Do you want to submit?')) {
        return;
      }

      return false;
    });
  }
}
})(jQuery, Drupal, this, this.document);
schlicki
la source
Parce que Drupal se lie à l'événement mousedown, votre gestionnaire d'événements de clic ne se déclenchera jamais.
Felix Eve
Drupal ne change pas la façon dont PHP ou JS fonctionne. Pourquoi n'écouterait-il PAS l'événement de clic? Ici Drupal est juste utilisé pour attacher le code JS. Une fois le site chargé, Drupal a fait son travail. Les auditeurs JS sont tous là, non? ;)
schlicki
Vous posez une bonne question et pour être honnête, je ne sais pas pourquoi l'événement click ne se déclenche pas. Cependant, après des tests approfondis, je peux confirmer que non. Probablement besoin d'avoir une lecture de ajax.js de Drupal pour avoir une meilleure compréhension.
Felix Eve