quarta-feira, 18 de dezembro de 2013

Evitar duplo submit com jQuery

No trabalho hoje me deparei com a necessidade de impedir que se façam múltiplos submits em uma página Web.

Na empresa onde trabalho não usamos asp.net MVC ou Web Forms, mas sim um framework próprio da empresa, feito sobre asp.net, que lembra muito o asp clássico.

Independente do ambiente ou framework, de ser em php, .net etc, se não houver um recurso nativo para evitar isso então você deve se preocupar: lentidão para enviar a página e o usuário com "dedinho nervoso" clicando em enviar mil vezes por segundo, levando a múltiplos posts (submits) e a inserir mútiplos dados idênticos no seu banco de dados.

Além do trabalho server-side, de validação, prevenção de duplicidades na camada de persistência, redirect para uma página de sucesso etc, deve haver alguma coisa client-side para prevenir o submit duplo.

Com javascript é possível desabilitar o botão no momento do click, e evitar que ele seja pressionado novamente.
Se for um Button do tipo AspButton (System.Web.UI.WebControls.Button), da paleta Web do Visual Studio, num ambiente Web Forms, talvez você deseje adicionar o script como um atributo do botão, no evento load da página.

Com jQuery fica muito fácil, e funciona de uma vez para todas as forms e botões de uma página.

De todos os scripts que eu fucei o desse site http://thepugautomatic.com/2008/07/jquery-double-submission/ me pareceu o melhor. Ele praticamente cria uma função nova no jQuery, que você pode reusar em todas as páginas com uma linha de código.



//isso você coloca em um arquivo js externo, a ser chamado depois do jquery, ou na tag script de uma página
            jQuery.fn.preventDoubleSubmit = function() {
              jQuery(this).submit(function() {
                if (this.beenSubmitted)
                  return false;
                else
                  this.beenSubmitted = true;
              });
            };

//isso você coloca dentro do $(document).ready
    $(document).ready(function() 
    { 
      jQuery('form').preventDoubleSubmit(); 
    }


E está pronto: só de incluir essa pequena linha já resolve todos os problemas de dedo nervoso nas suas páginas.

Tentei também outros scripts, e o script abaixo também funcionou muito bem, embora peque quanto à elegância e ao reaproveitamento de código:

//esse embora diferente, faz a mesma coisa que o script acima: atua na interceptação do submit da form, mas desabilita os botões logo após o submit
$('form').submit(function() {
                if(typeof jQuery.data(this, "disabledOnSubmit") == 'undefined') {
                    jQuery.data(this, "disabledOnSubmit", { submited: true });
                    $('input[type=submit], input[type=button]', this).each(function() {
                        $(this).attr("disabled", "disabled");
                  });
                  //$('input[type=submit], input[type=button]', this).attr("disabled", "disabled");
                  return true;
            }
            else
            {
                return false;
            }
});

Esse terceiro script não funcionou muito bem, não sei explicar porque, mas ele deveria atuar no evento click, sumindo com o botão (ou desabilidando-o) logo o clique aconteça.

//esse atua de forma diferente: tenta interceptar o click
            $('input[type=submit], input[type=button]').live('click', function(){
               
                if(!$(this).prop("disabled"))
                {
                    $('input[type=submit], input[type=button]', this).each(function() {
                        $(this).attr("disabled", "disabled");
                    });
                    
                    //$('input[type=submit], input[type=button]', this).attr("disabled", "disabled");

                    return true;
                }
                else
                {
                    return false;
                }
            });

Uma coisa que  o primeiro script não faz é desabilitar ou esconder os botões, mas basta adicionar a linha $('input[type=submit], input[type=button]', this).attr("disabled", "disabled") para fazer isso. Detalhe que em ambos os scripts eu deixei essa linha comentada. É que as linhas acima já fazem isso varrendo todos os resultados do seletor com um .each(), onde eu posso aproveitar para colocar mais comportamento nesse código.

No seletor, estou passando  thi como contexto, como visto na linha acima. Não sei porque, se omitir isso, não conseguimos fazer sequer uma submissão.

Fique atento, no jQuery, à diferença entre .prop e .attr, explicarei isso num próximo post.

Um comentário:

Postagens populares

Marcadores

delphi (60) C# (31) poo (21) Lazarus (19) Site aos Pedaços (15) sql (13) Reflexões (10) .Net (9) Humor (9) javascript (9) ASp.Net (8) api (8) Básico (6) Programação (6) ms sql server (5) Web (4) banco de dados (4) HTML (3) PHP (3) Python (3) design patterns (3) jQuery (3) livros (3) metaprogramação (3) Ajax (2) Debug (2) Dicas Básicas Windows (2) Pascal (2) games (2) linguagem (2) música (2) singleton (2) tecnologia (2) Anime (1) Api do Windows (1) Assembly (1) Eventos (1) Experts (1) GNU (1) Inglês (1) JSON (1) SO (1) datas (1) developers (1) dicas (1) easter egg (1) firebird (1) interfaces (1) introspecção (1) memo (1) oracle (1) reflexão (1)