Al hacer clic en un botón dentro de un formulario, se actualiza la página

217

Tengo un formulario en Angular que tiene dos etiquetas de botones. Un botón envía el formulario ng-click. El otro botón es solo para navegación ng-click. Sin embargo, cuando se hace clic en este segundo botón, AngularJS está causando una actualización de la página que activa un 404. He dejado caer un punto de interrupción en la función y está activando mi función. Si hago algo de lo siguiente, se detiene:

  1. Si elimino el ng-click, el botón no causa una actualización de la página.
  2. Si comento el código en la función, no se actualiza la página.
  3. Si cambio la etiqueta del botón a una etiqueta de anclaje ( <a>) con href="", entonces no causa una actualización.

Esta última parece ser la solución más simple, pero ¿por qué AngularJS incluso ejecuta algún código después de mi función que hace que la página se vuelva a cargar? Parece un error.

Aquí está la forma:

<form class="form-horizontal" name="myProfile" ng-switch-when="profile">
  <fieldset>
    <div class="control-group">
      <label class="control-label" for="passwordButton">Password</label>
      <div class="controls">
        <button id="passwordButton" class="secondaryButton" ng-click="showChangePassword()">Change</button>
      </div>
    </div>

    <div class="buttonBar">
      <button id="saveProfileButton" class="primaryButton" ng-click="saveUser()">Save</button>
    </div>
  </fieldset>
</form>

Aquí está el método del controlador:

$scope.showChangePassword = function() {
  $scope.selectedLink = "changePassword";
};
chubbsondubs
fuente
Vea si este es su problema github.com/angular/angular.js/issues/1238 (Desafortunadamente, no conozco lo suficiente sobre github como para saber si esta solución está en la versión 1.0.1 o no) .
Mark Rajcok
Vi esa, pero no estoy cambiando la ubicación, así que no creo que se aplique. A menos que este otro botón haga que se envíe, pero no se define como un tipo de envío, y cuando quito el ng-clic, el botón no envía el formulario.
chubbsondubs
Sería genial que pudieras proporcionar una demostración funcional de este problema. Quizás comenzando con: Angular Plnkr
Pete BD

Respuestas:

471

Si echa un vistazo a la especificación W3C , parece que lo más obvio es marcar los elementos de su botón type='button'cuando no desea que se envíen.

Lo que hay que tener en cuenta en particular es dónde dice

Un elemento de botón sin atributo de tipo especificado representa lo mismo que un elemento de botón con su atributo de tipo establecido en "enviar"

LOAS
fuente
44
Tengo el mismo problema que OP pero mis botones tienen el tipo especificado, y aún así, hacer clic en actualizar. ¿Algún otro lugar donde pueda mirar?
Mateo Velenik
Eso me sugiere que su problema está en javascript. El problema que aborda mi respuesta es más una cuestión entre dom y el navegador. Es probable que algunos javascript que manejan el clic de su botón causen la recarga que ve. Happy hunting;)
LOAS
Esto es exactamente lo que estaba buscando. Fue muy molesto en mi página porque se suponía que solo mostraba los errores y no los enviaba.
reaper_unique
Tengo mis botones marcados con type = "button" y también tengo el problema. En mi controlador ng-click, tengo $ event.stopPropagation (). Cuando lo quito, no se recarga. Aunque lo necesito. ¿Alguna idea de por qué causa una recarga de página?
felixfbecker
@freshfelicio: intenta agregar también $event.preventDefault(), eso ayudó en mi caso. Pero no tengo explicaciones de por qué: - \
Tim Büthe
72

Puede intentar evitar el controlador predeterminado:

html:

<button ng-click="saveUser($event)">

js:

$scope.saveUser = function (event) {
  event.preventDefault();
  // your code
}
ventaja
fuente
¡Agradable! Realmente traído a mi escenario!
Richard
2
Esto funcionó para nosotros, cuando usamos AngularJS dentro de un formulario de SharePoint. Tuve que agregar "event.stopPropagation ();" aunque también.
Nick DeMayo
19

Debe declarar el atributo ng-submit={expression}en su <form>etiqueta.

De los documentos de ngSubmit http://docs.angularjs.org/api/ng.directive:ngSubmit

Habilita las expresiones angulares vinculantes para enviar eventos.

Además, evita la acción predeterminada (que para el formulario significa enviar la solicitud al servidor y volver a cargar la página actual).

Shane Stillwell
fuente
3
Además, asegúrese de no tener la propiedad 'action' establecida en el formulario: form (action = "/ login", lng-submit = "login ()") Ya que esto hará que la página se actualice incluso si tiene ng-submit set .
jenso
Enviar un formulario y evitar la acción predeterminada Dado que el papel de los formularios en las aplicaciones angulares del lado del cliente es diferente al de las aplicaciones clásicas de ida y vuelta, es conveniente que el navegador no traduzca el envío del formulario en una recarga de página completa que envíe los datos al servidor . En cambio, se debe activar alguna lógica de JavaScript para manejar el envío del formulario de manera específica de la aplicación. Por este motivo, Angular evita la acción predeterminada (envío de formulario al servidor) a menos que el elemento <form> tenga un atributo de acción especificado. - docs.angularjs.org/api/ng.directive:form
Jignesh Gohel
Tengo un formulario con ng-submit = {expression} y un botón con type = "submit". Funciona igual de bien, excepto en BB10. Si utilizo Enviar del teclado BB10, la página se actualizará. Si uso el botón que he declarado en mi formulario, funciona bien.
Michael
Esto no funciona para mí. Seguí las instrucciones exactamente. La página aún se publica de nuevo
meffect
18

Yo uso la directiva para evitar el comportamiento predeterminado:

module.directive('preventDefault', function() {
    return function(scope, element, attrs) {
        angular.element(element).bind('click', function(event) {
            event.preventDefault();
            event.stopPropagation();
        });
    }
});

Y luego, en html:

<button class="secondaryButton" prevent-default>Secondary action</button>

Esta directiva también se puede usar con <a>y todas las demás etiquetas

pleerock
fuente
+1 ¡Gracias! Esto es útil cuando no tiene acceso a la <form>etiqueta y, por lo tanto, no puede usar la ng-submitdirectiva.
jackvsworld
gracias por este, pero también necesito cancelar ng-click en una directiva
boi_echos
Esto también evita que el formulario active la devolución de llamada ng-submit, ¿verdad?
Jhourlad Estrella
5

Puede mantener <button type="submit">, pero debe eliminar el atributo action=""de <form>.

Anderson Ferreira
fuente
2

Me pregunto por qué nadie propuso la solución posiblemente más simple:

no uses un <form>

A <whatever ng-form>IMHO hace un mejor trabajo y sin un formulario HTML, no hay nada que enviar el navegador en sí. Cuál es exactamente el comportamiento correcto cuando se usa angular.

maaartinus
fuente
¿Cómo aplicar el formulario válido al hacer clic y luego sin etiqueta de formulario?
Rizwan Patel
1
@RizwanPatel, supongo, no entiendo, pero con ng-form=someForm, obtienes $scope.someFormy tiene un $validcampo. Entonces consigo todo lo que necesito <button ng-disabled="!someForm.$valid">.
maaartinus
1

Agregue acción a su formulario.

<form action="#">

Swapnil Patwa
fuente
1

Es posible que esta respuesta no esté directamente relacionada con la pregunta. Es solo para el caso cuando envía el formulario utilizando scripts.

De acuerdo con el código ng-submit

 var handleFormSubmission = function(event) {
  scope.$apply(function() {
    controller.$commitViewValue();
    controller.$setSubmitted();
  });

  event.preventDefault();
};

formElement[0].addEventListener('submit', handleFormSubmission);

Agrega el detector de eventos de envío en el formulario. Pero el controlador de eventos de envío no se llamará cuando el envío se inicia llamando a form.submit (). En este caso, ng-submit no impedirá la acción predeterminada, debe llamar a preventDefault usted mismo en el controlador ng-submit;

Para proporcionar una respuesta razonablemente definitiva, el elemento 5 del Algoritmo de envío de formularios HTML establece que un formulario solo envía un evento de envío si no se envió llamando al método de envío (lo que significa que solo envía un evento de envío si se envía mediante un botón u otro método implícito método, por ejemplo, presionar enter mientras el foco está en un elemento de texto de tipo de entrada).

Ver formulario enviado usando submit () desde un enlace no puede ser capturado por el controlador de envío

usuario1577263
fuente
0

El primer botón envía el formulario y el segundo no

<body>
<form  ng-app="myApp" ng-controller="myCtrl" ng-submit="Sub()">
<div>
S:<input type="text" ng-model="v"><br>
<br>
<button>Submit</button>
//Dont Submit
<button type='button' ng-click="Dont()">Dont Submit</button>
</div>
</form>

<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.Sub=function()
{
alert('Inside Submit');
}

$scope.Dont=function()
{
$scope.v=0;
}
});
</script>

</body>
Amay Kulkarni
fuente
0

Simplemente agregue el FormsModuleen la importsmatriz de app.module.tsarchivos y agregue import { FormsModule } from '@angular/forms';en la parte superior de este archivo ... esto funcionará.

Sahil Sharma
fuente