Cómo agregar una ventana emergente de confirmación de JS al hacer clic en un botón #ajax

10

Tengo una entrada de botón FAPI básica que está habilitada para #ajax y está funcionando bien, pero quiero agregar un JS "¿Estás seguro?" ventana emergente de confirmación al hacer clic en el botón antes de que el código realmente se ejecute, y no estoy seguro de cómo hacerlo porque JS de FAPI parece estar comiendo el clic antes de que pueda acceder a él sin importar lo que haga.

Intenté agregar un controlador onclick en línea, así:

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

... lo que no ayuda, y también he intentado agregar:

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

en JS de mi módulo que también se ignora.

¿Alguna otra idea? ¿Hay alguna manera de agregar un controlador de envío a la parte superior de la pila que Drupal #ajax reconocerá?

Mike Crittenden
fuente

Respuestas:

15

Drupal es un framework PHP, y es sorprendente la cantidad de cosas sofisticadas de AJAX que puedes obtener usando eso y el FAPI. Pero tiene sus límites y para un caso de uso como este, sugeriría que use JavaScript personalizado. Además, en lugar de usar el cuadro de diálogo de JavaScript, puede usar jQuery UI para crear un cuadro de diálogo temático.

De todos modos, el problema que enfrenta probablemente se deba a que usa AJAX en el botón de envío. Dado que está utilizando AJAX para la llamada de eliminación real, preventDefaulty similares no funcionarán.

Lo que tendrías que hacer es algo como esto. (Esto no se ha probado ampliamente, pero debería funcionar).

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
fuente
También agregué $ ('. Confirmar'). Unbind ('mousedown'); Evento 'mousedown' de Drupal listerns también.
milkovsky
¿No se romperá el botón si el usuario cancela el diálogo de confirmación y luego vuelve a hacer clic? (porque $('.confirm').unbind('click');) ... ¿o lo estoy leyendo mal? lo siento, no estoy familiarizado conunbind
ErichBSchulz
1
@ErichBSchulz Unbind solo se llama una vez, por el método adjunto que se llama al cargar la página.
googletorp
gist.github.com/guoxiangke/0dffa7722a67f052c7ce Tipo de error no capturado : No se puede leer la propiedad 'clic' de indefinido ?????? Tengo un formulario, en node / add / content-type, y lo ajax, uso js validate
bluesky_still
4

confirmando que Jeroen está arreglando el código de googletorp.

Sin embargo, yo mismo descubrí que las coincidencias del tipo "mousedown" tienen que volver a estar libres y vinculadas. Entonces, el código que funcionó para mí es el siguiente:

(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
fuente
Realmente es una pérdida de recursos clonar objetos DOM a menos que realmente los necesite.
googletorp
Hola, me encontré con la misma pregunta, todo va bien, pero me encontré con un error js: "Error de tipo no capturado: no se puede leer la propiedad 'clic' de indefinido" también para "mousedown".
bluesky_still
Esta es la única solución que pude poner a trabajar. La clonación es clave aquí. Sin el clon, cuando haces clic en Aceptar, la alerta vuelve a aparecer instantáneamente.
Felix Eve
4

La pregunta es antigua, pero también me interesó. En mi opinión, la forma más fácil es usar el evento click en su definición de Ajax, porque Drupal usa el evento mousedown de manera predeterminada:

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

Luego solo necesita agregar un .mousedown()evento a su botón en su archivo Javascript, porque se activa antes del evento de clic:

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

Si aún desea que se llame a su Solicitud de Ajax con el evento mousedown, puede usar un evento personalizado:

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

Luego puede activar este evento en el .mousedown()caso de su archivo Javascript:

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

Ambas versiones funcionan!

Daniel
fuente
¡Si! Me gusta este porque hace lo que quieres: te da una idea del proceso comercial de Drupal al que puedes llamar cuando lo necesites. Nótese bien. Todavía necesitaba tener un preventDefaultcontrolador de clics para evitar el envío normal (no js) del formulario.
artfulrobot
0

¿Has intentado ejecutar tu JS dentro de un comportamiento de Drupal? Podría ser que su controlador de clics se adjunte después de Drupal.

De cualquier manera, debería poder desvincular el controlador de clics de Drupal en el botón para que se le llame primero y pueda llamar al controlador de clics Ajax de Drupal manualmente (y condicionalmente).

Adam DiCarlo
fuente
0

Respondiendo para notar que el código de googletorp no es 100% correcto.

Debe cambiar la línea donde se almacenan los eventos para esto:

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

De esta forma elimina cualquier problema de referencia de objetos, por lo que al desenlazar los eventos de clic, no se desenlaza también en su var;)

Además, tenga en cuenta que desde jQuery 1.8 el método .data () ha quedado en desuso. La obtención de datos de eventos ahora se realiza a través de una estructura de datos interna:

.data ("eventos") : jQuery almacena sus datos relacionados con eventos en un objeto de datos llamado (espere) eventos en cada elemento. Esta es una estructura de datos interna, por lo que en 1.8 se eliminará del espacio de nombre de datos de usuario para que no entre en conflicto con elementos del mismo nombre. Todavía se puede acceder a los datos de eventos de jQuery a través de jQuery._data (elemento, "eventos"), pero tenga en cuenta que esta es una estructura de datos interna que no está documentada y no debe modificarse.

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

Jeroen
fuente
0

Encontré muchas respuestas útiles arriba y pude hacer que mi formulario funcionara. En conjunto, esto es lo que funcionó para mi aplicación: un botón de formulario de eliminación con un cuadro de diálogo de confirmación y devolución de llamada AJAX para modificar el contenido de una lista de selección.

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

El elemento de formulario (lista de selección) a modificar:

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

El botón:

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

);

Y finalmente, la devolución de llamada AJAX:

function ajax_delete_callback ($form, $form_state) {

  // callback implementation code

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

He solucionado esto modificando el archivo drupal misc / ajax.jx.

Cree una copia del archivo ajax.js y colóquelo en cualquier módulo personalizado y modifique la Drupal.ajax = function (base, element, element_settings) { función en 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);   
     }    
},

esta trabajando bien para mi.

Hemant
fuente
1
Cuenta como núcleo de piratería, y probablemente debería evitarse.
Mołot
1
Y es completamente innecesario - es.wikipedia.org/wiki/Monkey_patch
Clive
Esta era la única forma en que podía hacer que este concepto funcionara sin mostrar cuadros de confirmación doble. La única excepción es que tuve que hacer que la instrucción if verificara si ajax.url == 'field_collection_remove_js'. ¿Quizás es por la versión de Drupal que estoy usando?
Richard
-1

Tal vez un poco viejo, pero me pregunto por qué no podemos usar:

(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
fuente
Debido a que Drupal se une al evento mousedown, su controlador de eventos click nunca se activará.
Felix Eve
Drupal no está cambiando la forma en que funciona PHP o JS. ¿Por qué NO escucha el evento click? Aquí Drupal solo se usa para adjuntar el código JS. Una vez que se carga el sitio, Drupal ha hecho su trabajo. Los oyentes de JS están ahí, ¿verdad? ;)
schlicki
Planteas una buena pregunta y, para ser sincero, no sé por qué no se activa el evento de clic. Sin embargo, después de extensas pruebas, puedo confirmar que no. Probablemente necesite leer el ajax.js de Drupal para comprenderlo mejor.
Felix Eve