Cómo evitar que los botones envíen formularios

917

En la página siguiente, con Firefox, el botón Eliminar envía el formulario, pero el botón Agregar no. ¿Cómo evito que el botón Eliminar envíe el formulario?

<html>

<head>
    <script type="text/javascript" src="jquery-1.3.2.min.js"></script>
    <script type="text/javascript">
        function addItem() {
            var v = $('form :hidden:last').attr('name');
            var n = /(.*)input/.exec(v);

            var newPrefix;
            if (n[1].length == 0) {
                newPrefix = '1';
            } else {
                newPrefix = parseInt(n[1]) + 1;
            }

            var oldElem = $('form tr:last');
            var newElem = oldElem.clone(true);
            var lastHidden = $('form :hidden:last');

            lastHidden.val(newPrefix);

            var pat = '=\"' + n[1] + 'input';

            newElem.html(newElem.html().replace(new RegExp(pat, 'g'), '=\"' + newPrefix + 'input'));
            newElem.appendTo('table');
            $('form :hidden:last').val('');
        }

        function removeItem() {
            var rows = $('form tr');
            if (rows.length > 2) {
                rows[rows.length - 1].html('');
                $('form :hidden:last').val('');
            } else {
                alert('Cannot remove any more rows');
            }
        }
    </script>
</head>

<body>
    <form autocomplete="off" method="post" action="">
        <p>Title:<input type="text" /></p>
        <button onclick="addItem(); return false;">Add Item</button>
        <button onclick="removeItem(); return false;">Remove Last Item</button>
        <table>
            <th>Name</th>

            <tr>
                <td><input type="text" id="input1" name="input1" /></td>
                <td><input type="hidden" id="input2" name="input2" /></td>
            </tr>
        </table>
        <input id="submit" type="submit" name="submit" value="Submit">
    </form>
</body>

</html>
Khanpo
fuente
¿Qué respuesta me recomiendan por favor?
sanepete

Respuestas:

1799

Estás utilizando un elemento de botón HTML5. Recuerde que la razón es que este botón tiene un comportamiento predeterminado de envío, como se indica en la especificación W3 como se ve aquí: Botón HTML5 W3C

Por lo tanto, debe especificar su tipo explícitamente:

<button type="button">Button</button>

para anular el tipo de envío predeterminado. Solo quiero señalar la razón por la que esto sucede =)

=)

Metafaniel
fuente
17
También deseo señalar que un elemento HTML que tiene un atributo type, uno de los cuales es button , no debería tener un tipo de envío predeterminado . Es simplemente idiota, y un gran error en la especificación. Uso botones en formularios todo el tiempo, e incluso si se tratara de un caso límite (que no lo es), aún tendría sentido que se envíe el tipo predeterminado.
dudewad
3
🤯 Pasé la mayor parte de esta semana molesto porque mi aplicación Electron se "actualizó" cuando abro un modal usando un botón dentro de un formulario. Sucedería una vez y luego la aplicación se comportó como esperaba. No tenía ni idea de lo que estaba pasando. ¡Esto fue! No tengo ningún problema con el tipo predeterminado que se envía. Parece un poco un problema, aunque dado que me ha llevado cinco años aprenderlo.
freethebees
44
Gracias a su referencia, acabo de enterarme de que hay un type = reset para el formulario. ¡Increíble!
Duong Nguyen
602

Establezca el tipo en sus botones:

<button type="button" onclick="addItem(); return false;">Add Item</button>
<button type="button" onclick="removeItem(); return false;">Remove Last Item</button>

... eso evitará que activen una acción de envío cuando se produzca una excepción en el controlador de eventos. Luego, arregle su removeItem()función para que no active una excepción:

function removeItem() {
  var rows = $('form tr');
  if ( rows.length > 2 ) {
    // change: work on filtered jQuery object
    rows.filter(":last").html('');
    $('form :hidden:last').val('');
  } else {
    alert('Cannot remove any more rows');
  }
}

Tenga en cuenta el cambio: su código original extrajo un elemento HTML del conjunto jQuery y luego trató de invocar un método jQuery, esto arrojó una excepción, lo que resultó en el comportamiento predeterminado del botón.

FWIW, hay otra forma en que podría ir con esto ... Conecte sus controladores de eventos usando jQuery, y use el método preventDefault () en el objeto de evento de jQuery para cancelar el comportamiento predeterminado por adelantado:

$(function() // execute once the DOM has loaded
{

  // wire up Add Item button click event
  $("#AddItem").click(function(event)
  {
    event.preventDefault(); // cancel default behavior

    //... rest of add logic
  });

  // wire up Remove Last Item button click event
  $("RemoveLastItem").click(function(event)
  {
    event.preventDefault(); // cancel default behavior

    //... rest of remove last logic
  });

});

...

<button type="button" id="AddItem" name="AddItem">Add Item</button>
<button type="button" id="RemoveLastItem" name="RemoveLastItem">Remove Last Item</button>

Esta técnica mantiene toda su lógica en un solo lugar, lo que facilita la depuración ... también le permite implementar un retroceso cambiando typelos botones de nuevo a submity manejando el lado del servidor de eventos; esto se conoce como discreto JavaScript .

Shog9
fuente
44
type = "button" no siempre funciona en Firefox para mí. Si js es lo suficientemente complicado y hay un error, Firefox enviará el formulario de todos modos. ¡Locura!
Matthew Lock
1
@MatthewLock: Difícilmente: un error en el script simplemente apaga ese bloque de código y la acción continúa como de costumbre. Intente invocar los métodos de evento jQuery e.preventDefault () y / o e.stopPropgation () como las primeras líneas del método. Ver stackoverflow.com/questions/2017755/... para aprender más
brichins
8
sin embargo, type = button nunca debe enviar el formulario, pase lo que
pase
1
return falsees muy importante a veces incluso lo usa para el botón de enviar ( onclick
Jamie
77
Creo que html es extraño aquí. Debe ser type = "button" por defecto, no enviando. Siempre es inesperado para mí ver ese envío por defecto. Es la excepción.
httpete
31

Hace algún tiempo necesitaba algo muy similar ... y lo conseguí.

Entonces, lo que pongo aquí es cómo hago los trucos para que un formulario pueda ser enviado por JavaScript sin ninguna validación y ejecutar validación solo cuando el usuario presiona un botón (generalmente un botón de envío).

Para el ejemplo, usaré un formulario mínimo, solo con dos campos y un botón de envío.

Recuerde lo que se desea: desde JavaScript debe poder enviarse sin ninguna comprobación. Sin embargo, si el usuario presiona dicho botón, la validación debe hacerse y el formulario debe enviarse solo si pasa la validación.

Normalmente todo comenzaría desde algo cerca de esto (eliminé todas las cosas adicionales que no son importantes):

<form method="post" id="theFormID" name="theFormID" action="">
   <input type="text" id="Field1" name="Field1" />
   <input type="text" id="Field2" name="Field2" />
   <input type="submit" value="Send" onclick="JavaScript:return Validator();" />
</form>

Vea cómo la etiqueta de formulario no tiene onsubmit="..." (recuerde que era una condición para no tenerla).

El problema es que el formulario siempre se envía, sin importar si onclickdevuelve trueofalse .

Si cambio type="submit"portype="button" , parece funcionar pero no funciona. Nunca envía el formulario, pero eso se puede hacer fácilmente.

Así que finalmente usé esto:

<form method="post" id="theFormID" name="theFormID" action="">
   <input type="text" id="Field1" name="Field1" />
   <input type="text" id="Field2" name="Field2" />
   <input type="button" value="Send" onclick="JavaScript:return Validator();" />
</form>

Y function Validator, donde return True;está, también agrego una oración de envío de JavaScript, algo similar a esto:

function Validator(){
   //  ...bla bla bla... the checks
   if(                              ){
      document.getElementById('theFormID').submit();
      return(true);
   }else{
      return(false);
   }
}

El id=""es solo para JavaScript getElementById, elname="" es sólo para que aparezca en los datos POST.

De esa manera funciona como lo necesito.

Lo pongo solo para las personas que no necesitan ninguna onsubmitfunción en el formulario, pero hacen alguna validación cuando el usuario presiona un botón.

¿Por qué no necesito enviar una etiqueta de formulario? Fácil, en otras partes de JavaScript necesito realizar un envío, pero no quiero que haya ninguna validación.

La razón: si el usuario es el que realiza el envío que quiero y necesito que se realice la validación, pero si es JavaScript, a veces necesito realizar el envío mientras que tales validaciones lo evitarían.

Puede sonar extraño, pero no cuando se piensa, por ejemplo: en un inicio de sesión ... con algunas restricciones ... como no permitir que se usen sesiones PHP y ¡no se permiten cookies!

Por lo tanto, cualquier enlace debe convertirse a dicho envío de formulario, para que no se pierdan los datos de inicio de sesión. Cuando todavía no se ha iniciado sesión, también debe funcionar. Por lo tanto, no se debe realizar ninguna validación en los enlaces. Pero quiero presentar un mensaje al usuario si el usuario no ha ingresado ambos campos, usuario y contraseña. Entonces, si falta uno, ¡no se debe enviar el formulario! Ahí está el problema.

Vea el problema: el formulario no debe enviarse cuando un campo está vacío solo si el usuario ha presionado un botón, si es un código JavaScript debe poder enviarse.

Si hago el trabajo en onsubmit la etiqueta del formulario, necesitaría saber si es el usuario u otro JavaScript. Como no se pueden pasar parámetros, no es posible directamente, por lo que algunas personas agregan una variable para saber si la validación debe hacerse o no. Lo primero en la función de validación es verificar el valor de la variable, etc. Demasiado complicado y el código no dice lo que realmente se desea.

Por lo tanto, la solución es no tener un envío en la etiqueta del formulario. Insead lo puso donde realmente se necesita, en el botón.

Por otro lado, ¿por qué poner el código de envío ya que conceptualmente no quiero la validación de envío? Realmente quiero la validación del botón.

No solo el código es más claro, es donde debe estar. Solo recuerde esto: - No quiero que JavaScript valide el formulario (eso debe ser hecho siempre por PHP en el lado del servidor) - Quiero mostrarle al usuario un mensaje diciendo que todos los campos no deben estar vacíos, que necesita JavaScript (cliente lado)

Entonces, ¿por qué algunas personas (piensan o me dicen) deben hacerlo en una validación integrada? No, conceptualmente no estoy haciendo una validación en el servidor del lado del cliente. Solo estoy haciendo algo en un botón, así que ¿por qué no dejar que se implemente?

Bueno, ese código y estilo funcionan perfectamente. En cualquier JavaScript que necesite para enviar el formulario que acabo de poner:

document.getElementById('theFormID').action='./GoToThisPage.php'; // Where to go
document.getElementById('theFormID').submit(); // Send POST data and go there

Y eso omite la validación cuando no la necesito. Simplemente envía el formulario y carga una página diferente, etc.

Pero si el usuario hace clic en el botón Enviar (también conocido como type="button"no type="submit"), la validación se realiza antes de permitir que se envíe el formulario y, si no es válido, no se envía.

Espero que esto ayude a otros a no probar código largo y complicado. Simplemente no lo use onsubmitsi no es necesario, y úselo onclick. Pero sólo recuerda a cambiar type="submit"a type="button"y por favor no se olvide de hacer el submit()de JavaScript.

z666zz666z
fuente
28

Estoy de acuerdo con Shog9, aunque en su lugar podría usar:

<input type = "button" onClick="addItem(); return false;" value="Add Item" />

Según w3schools , la <button>etiqueta tiene un comportamiento diferente en diferentes navegadores.

poundifdef
fuente
18

Supongamos que su formulario HTML tiene id="form_id"

<form id="form_id">
<!--your HTML code-->
</form>

Agregue este fragmento de jQuery a su código para ver el resultado,

$("#form_id").submit(function(){
  return false;
});
Prateek Joshi
fuente
18

Simplemente puede obtener la referencia de sus botones usando jQuery y evitar su propagación como se muestra a continuación:

 $(document).ready(function () {
    $('#BUTTON_ID').click(function(e) {

            e.preventDefault();
            e.stopPropagation();
            e.stopImmediatePropagation();

            return false;
    });});
Ata Iravani
fuente
2
e.preventDefault(); e.stopPropagation();es suficiente para que las cosas funcionen. e.stopImmediatePropagation()esto arroja un error de método indefinido en Chrome.
Subroto
14

$("form").submit(function () { return false; }); eso evitará que el botón se envíe o simplemente puede cambiar el tipo de botón a "botón" en <input type="button"/>lugar de <input type="submit"/> que solo funcionará si este botón no es el único botón en este formulario.

Shiala
fuente
2
Esto es para jQuery, un equivalente en Javascript es: myform.onsubmit = function () {return false} ... también, incluso si elimina el botón de envío, el formulario también podría enviarse presionando enter desde otro campo de formulario.
Synexis
10

Este es un error html5 como se ha dicho, aún puede tener el botón como envío (si desea cubrir tanto a los usuarios de JavaScript como a los que no lo usan) utilizándolo como:

     <button type="submit" onclick="return false"> Register </button>

De esta forma, cancelará el envío, pero seguirá haciendo lo que esté haciendo en jquery o en la función de JavaScript y enviará a los usuarios que no tengan JavaScript.

sagits
fuente
8

Estoy seguro de que en FF el

removeItem 

la función encuentra un error de JavaScript, esto no sucedió en IE

Cuando aparece el error de JavaScript, el código "return false" no se ejecutará, haciendo que la página se regrese

Alin Vasile
fuente
8

La devolución false impide el comportamiento predeterminado. pero el retorno falso rompe el burbujeo de eventos de clic adicionales. Esto significa que si hay otros enlaces de clic después de que se llama a esta función, esos otros no se consideran.

 <button id="btnSubmit" type="button">PostData</button>
 <Script> $("#btnSubmit").click(function(){
   // do stuff
   return false;
}); </Script>

O simplemente puedes poner así

 <button type="submit" onclick="return false"> PostData</button>
Sunil Dhappadhule
fuente
7

Simplemente agregue e.preventDefault();su método para evitar que su página envíe formularios.

function myFunc(e){
       e.preventDefault();
}

De acuerdo con los documentos web de MDN

El método preventDefault () de la interfaz de eventos le dice al agente de usuario que si el evento no se procesa explícitamente, su acción predeterminada no debe tenerse en cuenta como lo haría normalmente. El evento continúa propagándose como de costumbre, a menos que uno de sus oyentes llame stopPropagation ()o stopImmediatePropagation (), cualquiera de los cuales termine la propagación.

Mselmi Ali
fuente
6

Configure su botón de manera normal y use event.preventDefault como ...

   <button onclick="myFunc(e)"> Remove </button>  
   ...
   ...

   In function...

   function myFunc(e){
       e.preventDefault();
   }
Vishal
fuente
4
return false;

Puede devolver falso al final de la función o después de la llamada a la función.

Mientras sea lo último que suceda, el formulario no se enviará.

WonderWorker
fuente
2

Aquí hay un enfoque simple:

$('.mybutton').click(function(){

    /* Perform some button action ... */
    alert("I don't like it when you press my button!");

    /* Then, the most important part ... */
    return false;

});
axiom82
fuente
1

El siguiente código de muestra le muestra cómo evitar que el clic de botón envíe el formulario.

Puedes probar mi código de muestra:

 <form autocomplete="off" method="post" action="">
   <p>Title:
     <input type="text" />
   </p>
   <input type="button" onclick="addItem()" value="Add Item">
   <input type="button" onclick="removeItem()" value="Remove Last Item">
   <table>
     <th>Name</th>

     <tr>
       <td>
         <input type="text" id="input1" name="input1" />
       </td>
       <td>
         <input type="hidden" id="input2" name="input2" />
       </td>
     </tr>
   </table>
   <input id="submit" type="submit" name="submit" value="Submit">
 </form>
<script language="javascript">
function addItem() {
return false;
}

function removeItem() {
return false;
}
</script>
El KNVB
fuente
0

No puedo probar esto en este momento, pero creo que podría usar el método preventDefault de jQuery .

Tyler Rash
fuente
0

La función removeItem en realidad contiene un error, lo que hace que el botón del formulario haga su comportamiento predeterminado (enviar el formulario). La consola de error de JavaScript generalmente dará un puntero en este caso.

Consulte la función removeItem en la parte de JavaScript:

La línea:

rows[rows.length-1].html('');

no funciona Intenta esto en su lugar:

rows.eq(rows.length-1).html('');
ylebre
fuente