So fügen Sie ein JS-Bestätigungs-Popup hinzu, wenn Sie auf eine #ajax-Schaltfläche klicken

10

Ich habe eine grundlegende FAPI-Tasteneingabe, die #ajax aktiviert ist und gut funktioniert, aber ich möchte eine JS hinzufügen. "Sind Sie sicher?" Bestätigungs-Popup beim Klicken auf die Schaltfläche, bevor der Code tatsächlich ausgeführt wird, und ich bin mir nicht sicher, wie ich das tun soll, da JS von FAPI den Klick zu essen scheint, bevor ich darauf zugreifen kann, egal was ich tue.

Ich habe versucht, einen Inline-Onclick-Handler hinzuzufügen, wie folgt:

$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
  ),
);

... was nicht hilft, und ich habe auch versucht hinzuzufügen:

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

im JS meines Moduls, das ebenfalls ignoriert wird.

Irgendwelche anderen Ideen? Gibt es eine Möglichkeit, einen Submit-Handler oben im Stapel hinzuzufügen, den Drupal #ajax erkennt?

Mike Crittenden
quelle

Antworten:

15

Drupal ist ein PHP-Framework, und es ist erstaunlich, wie viel ausgefallenes AJAX-Material Sie mit diesem und dem FAPI erhalten können. Aber es hat Grenzen und für einen Anwendungsfall wie diesen würde ich vorschlagen, dass Sie benutzerdefiniertes JavaScript verwenden. Anstatt das normalerweise JavaScript-Dialogfeld zu verwenden, können Sie stattdessen auch die jQuery-Benutzeroberfläche verwenden, um ein themenbezogenes Dialogfeld zu erstellen.

Das Problem, mit dem Sie konfrontiert sind, wird wahrscheinlich dadurch verursacht, dass Sie AJAX auf der Schaltfläche "Senden" verwenden. Da Sie AJAX für den eigentlichen Löschaufruf verwenden preventDefaultund dergleichen nicht funktioniert.

Was Sie tun müssten, ist so etwas. (Dies ist nicht weit verbreitet, sollte aber funktionieren.)

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
quelle
Ich habe auch $ ('. Confirm') hinzugefügt. Unbind ('mousedown'); Drupal hört auch "Mousedown" -Ereignis.
Milkovsky
Wird die Schaltfläche dadurch nicht unterbrochen, wenn der Benutzer den Bestätigungsdialog abbricht und dann erneut klickt? (weil $('.confirm').unbind('click');) ... oder lese ich es falsch? Entschuldigung nicht vertraut mitunbind
ErichBSchulz
1
@ErichBSchulz Unbind wird nur einmal von der Attach-Methode aufgerufen, die beim Laden der Seite aufgerufen wird.
googletorp
gist.github.com/guoxiangke/0dffa7722a67f052c7ce Nicht erfasster TypeError: Eigenschaft 'click' von undefined kann nicht gelesen werden ?????? Ich habe ein Formular in Node / Add / Content-Type, und ich ajax es, benutze js validate
bluesky_still
4

Bestätigung, dass Jeroen den Code des Googletorp korrigiert.

Ich selbst habe jedoch festgestellt, dass die Ereignisse vom Typ "Mousedown" wieder geboten und gebunden werden müssen. Der Code, der für mich funktioniert hat, ist der folgende:

(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
quelle
Es ist wirklich eine Verschwendung von Ressourcen, DOM-Objekte zu klonen, es sei denn, Sie benötigen sie tatsächlich.
googletorp
Hallo, ich habe die gleiche Frage getroffen, alles läuft gut, aber ich habe einen js-Fehler festgestellt: "Nicht erfasster TypeError: Eigenschaft 'click' von undefined kann nicht gelesen werden" auch für "mousedown".
bluesky_still
Dies ist die einzige Lösung, die ich zur Arbeit bringen könnte. Klonen ist hier der Schlüssel. Wenn Sie ohne Klon auf OK klicken, wird die Warnung sofort wieder angezeigt.
Felix Eve
4

Die Frage ist alt, aber ich habe mich auch dafür interessiert. Meiner Meinung nach ist es am einfachsten, das Klickereignis in Ihrer Ajax-Definition zu verwenden, da Drupal standardmäßig das Mousedown-Ereignis verwendet:

$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',
  ),
);

Dann müssen Sie .mousedown()Ihrer Schaltfläche in Ihrer Javascript-Datei nur noch ein Ereignis hinzufügen , da es vor dem Klickereignis ausgelöst wird:

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

Wenn Ihre Ajax-Anfrage weiterhin mit dem Mousedown-Ereignis aufgerufen werden soll, können Sie ein benutzerdefiniertes Ereignis verwenden:

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

Dann können Sie dieses Ereignis im .mousedown()Falle Ihrer Javascript-Datei auslösen :

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

Beide Versionen funktionieren!

Daniel
quelle
Ja! Ich mag dieses, weil es macht, was Sie wollen: Es gibt Ihnen einen Überblick über den Drupal-Standardprozess, den Sie dann aufrufen können, wenn Sie ihn benötigen. Nb. Ich musste einen preventDefaultin meinem Klick-Handler haben, um zu verhindern, dass das Formular normal (nicht js) gesendet wird.
Artfulrobot
0

Haben Sie versucht, Ihr JS innerhalb eines Drupal-Verhaltens auszuführen? Es könnte einfach sein, dass Ihr Klick-Handler nach Drupal angehängt wird.

In beiden Fällen sollten Sie jedoch in der Lage sein, Drupals Klick-Handler auf der Schaltfläche zu lösen, damit Sie zuerst aufgerufen werden, und Sie können Drupals Ajax-Klick-Handler manuell (und bedingt) aufrufen.

Adam DiCarlo
quelle
0

Antworten, um festzustellen, dass der Code von googletorp nicht 100% korrekt ist.

Sie müssen die Zeile, in der die Ereignisse gespeichert sind, folgendermaßen ändern:

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

Auf diese Weise beseitigen Sie alle Objektreferenzprobleme. Wenn Sie also die Klickereignisse aufheben, wird die Bindung auch nicht in Ihrem var aufgehoben;)

Beachten Sie außerdem, dass die Methode .data () seit jQuery 1.8 veraltet ist. Das Abrufen von Ereignisdaten erfolgt jetzt über eine interne Datenstruktur:

.data („Ereignisse“) : jQuery speichert seine ereignisbezogenen Daten in einem Datenobjekt mit dem Namen (darauf warten) Ereignisse für jedes Element. Dies ist eine interne Datenstruktur, sodass diese in Version 1.8 aus dem Namensraum für Benutzerdaten entfernt wird, damit keine Konflikte mit gleichnamigen Elementen auftreten. Auf die Ereignisdaten von jQuery kann weiterhin über jQuery._data (Element, "Ereignisse") zugegriffen werden. Beachten Sie jedoch, dass dies eine interne Datenstruktur ist, die nicht dokumentiert ist und nicht geändert werden sollte.

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

Jeroen
quelle
0

Ich habe oben viele nützliche Antworten gefunden und konnte mein Formular zum Laufen bringen. Alles zusammen hat für meine Anwendung funktioniert: Eine Schaltfläche zum Löschen von Formularen mit einem Bestätigungsdialog und einem AJAX-Rückruf, um den Inhalt einer Auswahlliste zu ändern.

Das 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>
  ',
);

Das zu ändernde Formularelement (Auswahlliste):

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

Die Taste:

$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',
    ),

);

Und schließlich der AJAX-Rückruf:

function ajax_delete_callback ($form, $form_state) {

  // callback implementation code

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

Ich habe dies behoben, indem ich die Datei drupal misc / ajax.jx geändert habe.

Erstellen Sie eine Kopie der Datei ajax.js, fügen Sie ein beliebiges benutzerdefiniertes Modul ein und Drupal.ajax = function (base, element, element_settings) { ändern Sie die Funktion in 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);   
     }    
},

Es funktioniert gut für mich.

Hemant
quelle
1
Es zählt als Hacking-Kern und sollte wahrscheinlich vermieden werden.
Mołot
1
Und ist völlig unnötig - en.wikipedia.org/wiki/Monkey_patch
Clive
Dies war die einzige Möglichkeit, dieses Konzept ohne doppelte Bestätigungsfelder zum Laufen zu bringen. Die einzige Ausnahme ist, dass ich die if-Anweisung überprüfen lassen musste, ob ajax.url == 'field_collection_remove_js'. Vielleicht liegt das an der Version von Drupal, die ich verwende?
Richard
-1

Vielleicht ein bisschen alt, aber ich frage mich, warum wir nicht einfach verwenden können:

(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
quelle
Da Drupal das Mousedown-Ereignis bindet, wird Ihr Click-Event-Handler niemals ausgelöst.
Felix Eve
Drupal ändert nichts an der Funktionsweise von PHP oder JS. Warum sollte das Klickereignis NICHT abgehört werden? Hier wird Drupal nur zum Anhängen des JS-Codes verwendet. Sobald die Site geladen ist, hat Drupal seine Arbeit erledigt. JS-Hörer sind alle da, oder? ;)
schlicki
Sie werfen eine gute Frage auf und um ehrlich zu sein, weiß ich nicht, warum das Klickereignis nicht ausgelöst wird. Nach ausgiebigen Tests kann ich jedoch bestätigen, dass dies nicht der Fall ist. Wahrscheinlich müssen Sie Drupals ajax.js lesen, um ein besseres Verständnis zu erhalten.
Felix Eve