8

I am rendering ajax link as follows:

l(t('Click here'), 'mypath', array('attributes' => array('id' => 'my-id', 'class' => array('use-ajax'))));

How to display confirmation dialog before ajax request is called?

I do it as follows in javascript, like I have found on this thread:

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

 Drupal.ajax['my-id'].beforeSerialize = function () {  

      if(confirm('Are you sure?'))
          return true;
      else
          return false;

  }
 }
}

When I click on link, ajax request is not called but the dialog appears. It is ok. The problem is, that after I click "Cancel" in confirmation dialog, Ajax request is then called after closing the confirmation dialog.

Can anybody help, how to get the confirmation dialog work?

  • Considered using options.beforeSerialize or options.beforeSubmit in place of beforeSerialize? Documentation is pretty bad and I'm not sure which of these 3 is the right way, but it should take you less than 5 minutes to test both. – Mołot Sep 27 '13 at 8:30
  • Thanks for tip, but it didn't help – tomas.teicher Oct 2 '13 at 6:08
  • OK, sorry to hear that, as it left me a bit clueless and your question is reasonable and might be useful for me too. – Mołot Oct 2 '13 at 6:48
  • here you should find a way to go .. drupal.stackexchange.com/questions/14450/… – rémy Oct 8 '13 at 7:54
4

I don't think this is the best way to go about it as you are messing directly with Drupal's Ajax object.

The best way to do this, is to basically write your own click handler and handle the confirmation yourself, then trigger a Drupal AJAX call yourself.

Here is an example:

l(t('Click here'), 'mypath', array('attributes' => array('id' => 'my-id', 'class' => array('toms-ajax'))));

In your js file:

(function($) {

Drupal.behaviors.tomsAjaxLinks = {
  attach: function(context, settings) {
    $('.toms-ajax',context).once('toms-ajax').on('click', this.handleAjax);
  },
  handleAjax: function(e) {
    // Cache the anchor link
    var $element = $(this);

    // We need some unique id, either ID of link or create our own
    var nowStamp = new Date().getTime() + Math.floor(Math.random() * (1000 - 0) + 0);
    var base = $element.attr('id') || 'toms-ajax-'+ nowStamp;

    // Change the event type to load, so we can trigger it ourselves
    var drupal_ajax_settings = {
      url : $element.attr('href'),
      event : 'load',
      progress : {
        type: 'throbber',
        message : '',
      }
    };

    // Create the ajax object
    Drupal.ajax[base] = new Drupal.ajax(base, this, drupal_ajax_settings);

    // Your confirmation code e.g. Jquery UI Dialog or something
    // Open dialog
    if(yes) {
      $element.trigger('load');
    } else {
      // Dont trigger ajax
    }
  }
}; 

})(jQuery);

Essentially what this does is:

  1. Attaches the handleAjax function to your ".toms-ajax" links once to ensure we do not attach multiple event handlers
  2. On click, the handleAjax function is called
  3. A corresponding Drupal Ajax object is created with it's own unique ID. It is attached to the link and triggered on the event 'load'. You then handle the confirmation box.
  4. If the confirmation box confirms the ajaxcall, we simply trigger the 'load' event on the link object and therefore make the Drupal AJAX object do it's thing.
2

Based on @jnpWebDeveloper answer, but with some changes:

  • Support for re-attaching events to content loaded via ajax.
  • Support for custom message from data attribute of the element.
  • Code is production-ready (no need to change any variables etc.).

ajax-confirm-link.js

/**
 * @file
 * Handling of AJAX links with a confirmation message.
 *
 * @code
 * <a href="custom/nojs/path" class="use-ajax-confirm">Link with default message</a>
 * <a href="custom/nojs/path" class="use-ajax-confirm" data-use-ajax-confirm-message="Please confirm your action">Link with custom message</a>
 * @endcode
 */

/*global jQuery, Drupal*/

(function ($) {
  'use strict';
  Drupal.behaviors.ajaxConfirmLink = {
    attach: function (context, settings) {
      $('.use-ajax-confirm').filter('a').once('use-ajax-confirm').on('click', function (event) {
        var $this = $(this);
        // Allow to provide confirmation message in
        // data-use-ajax-confirm-message element attribute.
        var message = $this.data('use-ajax-confirm-message') || Drupal.t('Are you sure you want to do this?');

        if (confirm(message)) {
          // Create ajax event only if action was confirmed.
          var id = $this.attr('id');
          // Generate unique id, if the element does not already have one.
          if (!id || id.trim() == '') {
            id = 'use-ajax-confirm' + new Date().getTime() + Math.floor(Math.random() * 1000);
            $this.attr('id', id);
          }

          Drupal.ajax[id] = new Drupal.ajax(id, this, {
            // 'nojs' to 'ajax' replacement in path performed by Drupal.ajax().
            url: $this.attr('href'),
            event: 'load.use-ajax-confirm'
          });

          $this.trigger('load.use-ajax-confirm');
        }

        return false;
      });
    }
  };
}(jQuery));
0

If you check Drupal "ajax.js" file, link process is a special case.

Comment on "Drupal.ajax.prototype.beforeSerialize" says that function will never be called if it's not a form.

In that case, "options.beforeSerialize" is used before jQuery ajax call. So if you perform your confirmation here, you can click ok or cancel, ajax call will be always triggered.

But if you overload the "options.beforeSend" function instead, maybe your confirmation box should work because if that function return false, Ajax call is cancelled (jQuery Doc : http://api.jquery.com/jQuery.ajax/).

Here is the snippet used in "ajax.js" file

beforeSend: function (xmlhttprequest, options) {
  ajax.ajaxing = true;
  return ajax.beforeSend(xmlhttprequest, options);
}

The updated version, you can try it:

Drupal.ajax['my-id'].beforeSend: function (xmlhttprequest, options) {
  if(confirm('Are you sure?')){
      ajax.ajaxing = true;
      return ajax.beforeSend(xmlhttprequest, options);
  }
  return false;
}

I didn't have the time to test this snippet, upgrades and comment are welcome :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.