Como adicionar um pop-up de confirmação JS ao clicar no botão #ajax

10

Eu tenho uma entrada básica do botão FAPI que está #ajax ativada e está funcionando bem, mas quero adicionar uma JS "Tem certeza?" pop-up de confirmação ao clicar no botão antes da execução do código, e não sei como fazer isso porque o JS da FAPI parece estar consumindo o clique antes que eu possa acessá-lo, não importa o que eu faça.

Eu tentei adicionar um manipulador on-line on-line, assim:

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

... o que não ajuda, e eu também tentei adicionar:

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

no JS do meu módulo, que também é ignorado.

Alguma outra ideia? Existe uma maneira de adicionar um manipulador de envio ao topo da pilha que o Drupal #ajax reconhecerá?

Mike Crittenden
fonte

Respostas:

15

Drupal é uma estrutura PHP, e é incrível o quanto você pode obter coisas sofisticadas de AJAX usando isso e a FAPI. Mas tem limites e, para um caso de uso como esse, sugiro que você use JavaScript personalizado. Além disso, em vez de usar a caixa de diálogo geralmente JavaScript, você pode usar a interface do usuário do jQuery para criar uma caixa de diálogo visível.

De qualquer forma, o problema que você está enfrentando provavelmente é causado porque você usa o AJAX no botão enviar. Como você está usando o AJAX para a chamada de exclusão real, preventDefaulte coisas do gênero não funcionarão.

O que você teria que fazer é algo assim. (Isso não é amplamente testado, mas deve 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
fonte
Adicionei também $ ('. Confirm'). Unbind ('mousedown'); Evento 'mousedown' de drupal listerns também.
milkovsky
isso não interromperá o botão se o usuário cancelar a caixa de diálogo de confirmação e clicar novamente? (porque $('.confirm').unbind('click');) ... ou estou lendo errado? desculpe não familiarizado comunbind
ErichBSchulz
1
O @ErichBSchulz Unbind é chamado apenas uma vez, pelo método attach, que é chamado no carregamento da página.
googletorp
gist.github.com/guoxiangke/0dffa7722a67f052c7ce TypeError não capturado : Não é possível ler a propriedade 'clique' de undefined ?????? Eu tenho um formulário, no nó / add / tipo de conteúdo, e eu ajax-lo, use js validar
bluesky_still
4

confirmando que Jeroen está corrigindo o código do googletorp.

No entanto, eu mesmo descobri que os pares do tipo "mousedown" precisam ser abertos e ligados novamente. Portanto, o trecho de código que funcionou para mim é o seguinte:

(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
fonte
É realmente um desperdício de recursos clonar objetos DOM, a menos que você realmente precise deles.
googletorp
Olá, Encontrei a mesma pergunta, tudo corre bem, mas encontrei um erro js: "TypeError não capturado: Não é possível ler a propriedade 'clique' de indefinido" também para "mousedown".
Bluesky_still
Esta é a única solução que eu poderia começar a trabalhar. A clonagem é a chave aqui. Sem o clone, quando você clicar em ok, o alerta reaparecerá instantaneamente.
perfil completo de Felix Eve
4

A pergunta é antiga, mas eu também estava interessado nela. Na minha opinião, a maneira mais fácil é usar o evento click na sua definição de Ajax, porque o Drupal usa o evento mousedown como padrão:

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

Depois, basta adicionar um .mousedown()evento ao seu botão no seu arquivo Javascript, pois ele é acionado antes do evento click:

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

Se você ainda deseja que sua solicitação do Ajax seja chamada com o evento mousedown, é possível usar um evento personalizado:

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

Em seguida, você pode acionar esse evento no .mousedown()evento do seu arquivo Javascript:

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

Ambas as versões funcionam!

Daniel
fonte
sim! Eu gosto deste porque faz o que você deseja: fornece um controle sobre o processo disponível no Drupal, que você pode chamar quando precisar. Nb. Eu precisava ter um preventDefaultno meu manipulador de cliques para impedir o envio normal (não-js) de formulário.
Artfulrobot
0

Você já tentou executar seu JS dentro de um comportamento do Drupal? Pode ser que o seu manipulador de cliques esteja sendo anexado após o Drupal.

De qualquer forma, você deve conseguir desvincular o manipulador de cliques do Drupal no botão para ser chamado primeiro e poder chamar o manipulador de cliques do Ajax do Drupal manualmente (e condicionalmente).

Adam DiCarlo
fonte
0

Responder para observar que o código do googletorp não está 100% correto.

Você precisa alterar a linha em que os eventos são armazenados para isso:

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

Dessa forma, você elimina quaisquer problemas de referência de objeto; portanto, ao desvincular os eventos de clique, eles também não são desvinculados no seu var;)

Além disso, lembre-se de que, desde o jQuery 1.8, o método .data () ficou obsoleto. A obtenção de dados do evento agora é feita por meio de uma estrutura de dados interna:

.data (“events”) : o jQuery armazena seus dados relacionados a eventos em um objeto de dados chamado (aguarde) eventos em cada elemento. Essa é uma estrutura de dados interna; portanto, na versão 1.8, ela será removida do espaço de nome de dados do usuário para não entrar em conflito com itens com o mesmo nome. Os dados de eventos do jQuery ainda podem ser acessados ​​via jQuery._data (elemento, "events"), mas lembre-se de que essa é uma estrutura de dados interna que não está documentada e não deve ser modificada.

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

Jeroen
fonte
0

Encontrei muitas respostas úteis acima e consegui que meu formulário funcionasse. Juntando tudo, foi o que funcionou para o meu aplicativo: um botão de exclusão de formulário com uma caixa de diálogo de confirmação e retorno de chamada AJAX para modificar o conteúdo de uma lista de seleção.

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

O elemento do formulário (lista de seleção) a ser modificado:

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

O botão:

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

);

E, finalmente, o retorno de chamada AJAX:

function ajax_delete_callback ($form, $form_state) {

  // callback implementation code

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

Corrigi isso modificando o arquivo drupal misc / ajax.jx.

Crie uma cópia do arquivo ajax.js e coloque-o em qualquer módulo personalizado e modifiquei a Drupal.ajax = function (base, element, element_settings) { função antes de

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

Está funcionando bem para mim.

Hemant
fonte
1
Ele conta como núcleo de hackers e provavelmente deve ser evitado.
Mołot
1
E é completamente desnecessário - br.wikipedia.org/wiki/Monkey_patch
Clive
Esta foi a única maneira que eu consegui que esse conceito funcionasse sem mostrar caixas de confirmação dupla. A única exceção é que eu tive que fazer a instrução if verificar se ajax.url == 'field_collection_remove_js'. Talvez seja por causa da versão do Drupal que estou usando?
Richard
-1

Talvez um pouco velho, mas estou me perguntando por que não podemos simplesmente 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
fonte
Como o Drupal se liga ao evento do mouse, para que o manipulador de eventos de clique nunca seja acionado.
perfil completo de Felix Eve
O Drupal não está mudando a maneira como o PHP ou o JS funcionam. Por que NÃO ouvia o evento click? Aqui o Drupal é usado apenas para anexar o código JS. Depois que o site é carregado, o Drupal faz seu trabalho. Ouvintes JS estão todos lá, certo? ;)
schlicki
Você levanta uma boa pergunta e, para ser sincero, não sei por que o evento de clique não é acionado. No entanto, após testes extensivos, posso confirmar que não. Provavelmente, você precisa ler o ajax.js do Drupal para entender melhor.
Felix Eve