jQuery - evita o padrão e continua o padrão

102

Eu tenho um formulário que, quando enviado, preciso fazer alguns processamentos adicionais antes de enviar o formulário. Posso evitar o comportamento de envio de formulário padrão, depois faço meu processamento adicional (basicamente chamando a API do Google Maps e adicionando alguns campos ocultos ao formulário) - e então preciso enviar o formulário.

Existe uma maneira de "evitar o padrão" e, algum ponto depois, "continuar o padrão?"

StackOverflowNewbie
fonte
@FelixKling Você quis dizer stackoverflow.com/questions/7610871/… ?
M. Mimpen

Respostas:

53

Usar jQuery.one()

Anexe um manipulador a um evento para os elementos. O manipulador é executado no máximo uma vez por elemento por tipo de evento

$('form').one('submit', function(e) {
    e.preventDefault();
    // do your things ...

    // and when you done:
    $(this).submit();
});

O uso de oneprevenir também loop infinito porque este submitevento personalizado é detectado após o primeiro envio.

Aurel
fonte
2
ele será enviado após clicar novamente :(
curiosity
Provavelmente você enfrentará com loop infinito
Mehrdad HosseinNejad,
Loop infinito, a função deve ser .on não
.one
51

Quando você vincula o .submit()evento ao formulário e faz as coisas que deseja antes de retornar (verdadeiro), essas coisas acontecem antes do envio real.

Por exemplo:

$('form').submit(function(){
    alert('I do something before the actual submission');
    return true;
});

Exemplo simples

Outro exemplo em jquery.com: http://api.jquery.com/submit/#entry-examples

Ron van der Heijden
fonte
2
você está dizendo que o formulário não será submetido até que todo o código antes do "retorno verdadeiro;" declaração é executada?
Developarvin
2
Sim, é exatamente isso que a função submit () faz.
Ron van der Heijden
8
Não é um bom exemplo porque é sincrônico. E se eu precisar fazer uma chamada assíncrona? Portanto, o caso é "clique em enviar -> faça coisas assíncronas e não envie o formulário -> em retorno assíncrono preencha alguns campos do formulário -> envie o formulário a partir do retorno de chamada"
The Godfather
1
Que tal executar algum código jQuery assíncrono ?! Vai funcionar também?
candlejack
isso funciona muito bem para mim. Eu uso para controlar as coisas antes de enviar e se as coisas não estiverem certas eu uso "return false". Procurei essa solução por um dia. Muito obrigado.
livefreeor de
26

Eu apenas faria:

 $('#submiteButtonID').click(function(e){
     e.preventDefault();
     //do your stuff.
     $('#formId').submit();
 });

Ligue preventDefaultprimeiro e use a submit()função depois, se precisar apenas enviar o formulário

bipen
fonte
não envolva lógica dentro de seu manipulador de eventos de clique. delegue a responsabilidade a outros.
Royi Namir
27
Isso pressupõe que você clicará em um botão. E se o usuário simplesmente clicar no botão "entrar" no formulário? Isso também enviará o formulário. Portanto, provavelmente não é uma boa ideia confiar que o botão enviar será clicado.
StackOverflowNewbie
Eu estava apenas dando um exemplo de um clique ... já que não havia códigos relacionados mencionados na pergunta ...
bipen
2
Em qualquer caso, o snippet que você forneceu só funcionará se o usuário clicar em um botão. Não é assim que os formulários funcionam. Alguma outra sugestão?
StackOverflowNewbie
vincule o clique, evite seu padrão e acione o clique do botão enviar
candlejack
18

Usando desta forma, você fará um loop infinito em seu JS. para fazer uma maneira melhor, você pode usar o seguinte

var on_submit_function = function(evt){
    evt.preventDefault(); //The form wouln't be submitted Yet.
    (...yourcode...)

    $(this).off('submit', on_submit_function); //It will remove this handle and will submit the form again if it's all ok.
    $(this).submit();
}

$('form').on('submit', on_submit_function); //Registering on submit.

Espero que ajude! Obrigado!

Joepreludian
fonte
a melhor maneira, na verdade, variação com função assíncrona - gist.github.com/BjornMelgaard/8ba0ee9d07c20dd8c8b3550c9df3e9ef
srghma
@bjornmelgaard Devo lembrar que o assíncrono não é padrão .
Valerio Bozz
6

Esta é, IMHO, a solução mais genérica e robusta (se suas ações forem acionadas pelo usuário, por exemplo, 'o usuário clica em um botão'):

  • a primeira vez que um manipulador é chamado, verifique quem o acionou:
    • se um usuário o manipulou - faça suas coisas e, em seguida, acione-o novamente (se quiser) - programaticamente
    • caso contrário - não faça nada (= "continuar padrão")

Como exemplo, observe esta solução elegante para adicionar "Tem certeza?" pop-up para qualquer botão apenas decorando um botão com um atributo. Continuaremos condicionalmente com o comportamento padrão se o usuário não cancelar.

1. Vamos adicionar a cada botão que desejamos um pop-up "tem certeza" um texto de aviso:

<button class="btn btn-success-outline float-right" type="submit"  ays_text="You will lose any unsaved changes... Do you want to continue?"                >Do something dangerous</button>

2. Anexe manipuladores a TODOS esses botões:

$('button[ays_text]').click(function (e, from) {
    if (from == null) {  // user clicked it!
        var btn = $(this);
        e.preventDefault();
        if (confirm() == true) {
            btn.trigger('click', ['your-app-name-here-or-anything-that-is-not-null']);
        }
    }
    // otherwise - do nothing, ie continue default
});

É isso aí.

igorludi
fonte
1
Ótima resposta! Eu não sabia que você poderia passar um argumento extra para .trigger ()
James Hibbard
5
$('#myform').on('submit',function(event){
  // block form submit event
  event.preventDefault();

  // Do some stuff here
  ...

  // Continue the form submit
  event.currentTarget.submit();
});
Udayantha Udy Warnasuriya
fonte
3

Com jQuerye uma pequena variação da resposta de @Joepreludian acima:

Pontos importantes a serem lembrados:

  • .one(...) em vez de .on(...) or .submit(...)
  • namedfunção em vez de, anonymous functionpois iremos referenciá-la dentro do callback.

$('form#my-form').one('submit', function myFormSubmitCallback(evt) {
    evt.stopPropagation();
    evt.preventDefault();
    var $this = $(this);
    if (allIsWell) {
        $this.submit(); // submit the form and it will not re-enter the callback because we have worked with .one(...)
    } else {
        $this.one('submit', myFormSubmitCallback); // lets get into the callback 'one' more time...
    }
});

Você pode alterar o valor da allIsWellvariável no snippet abaixo para trueou falsepara testar a funcionalidade:

$('form#my-form').one('submit', function myFormSubmitCallback(evt){
  evt.stopPropagation();
  evt.preventDefault();
  var $this = $(this);
  var allIsWell = $('#allIsWell').get(0).checked;
  if(allIsWell) {
    $this.submit();
  } else {
    $this.one('submit', myFormSubmitCallback);
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form action="/" id="my-form">
  <input name="./fname" value="John" />
  <input name="./lname" value="Smith" />
  <input type="submit" value="Lets Do This!" />
  <br>
  <label>
    <input type="checkbox" value="true" id="allIsWell" />
    All Is Well
  </label>
</form>

Boa sorte...

Akash
fonte
2

Em uma forma de Javascript puro, você pode enviar o formulário após evitar o padrão.

Isso ocorre porque HTMLFormElement.submit() nunca chama o onSubmit(). Portanto, estamos contando com essa estranheza de especificação para enviar o formulário como se ele não tivesse um manipulador onsubmit personalizado aqui.

var submitHandler = (event) => {
  event.preventDefault()
  console.log('You should only see this once')
  document.getElementById('formId').submit()
}

Veja este violino para uma solicitação síncrona.


Esperar que uma solicitação assíncrona termine é tão fácil:

var submitHandler = (event) => {
  event.preventDefault()
  console.log('before')
  setTimeout(function() {
    console.log('done')
    document.getElementById('formId').submit()
  }, 1400);
  console.log('after')
}

Você pode verificar meu violino para obter um exemplo de solicitação assíncrona.


E se você está disposto a cumprir promessas:

var submitHandler = (event) => {
  event.preventDefault()
  console.log('Before')
    new Promise((res, rej) => {
      setTimeout(function() {
        console.log('done')
        res()
      }, 1400);
    }).then(() => {
      document.getElementById('bob').submit()
    })
  console.log('After')
}

E aqui está o pedido .

Alairock
fonte
1

Você pode usar o e.preventDefault()qual interromperá a operação atual.

do que você pode fazer$("#form").submit();

 $('#form').submit(function (e)
{
    return !!e.submit;
});
if(blabla...)
{...
}
else
{
    $('#form').submit(
    {
        submit: true
    });
}
Royi Namir
fonte
isso é muito confuso para mim .. isso não vai ficar dando voltas e mais voltas?
dapidmini
1

"Injeção de validação sem loop de envio":

Só quero verificar o reCaptcha e outras coisas antes da validação do HTML5, então fiz algo assim (a função de validação retorna verdadeiro ou falso):

$(document).ready(function(){
   var application_form = $('form#application-form');

   application_form.on('submit',function(e){

        if(application_form_extra_validation()===true){
           return true;
        }

        e.preventDefault();

   });
});
Dennis Heiden
fonte