Clicar em um botão em um formulário causa a atualização da página

217

Eu tenho um formulário no Angular que possui duas tags de botões. Um botão envia o formulário ng-click. O outro botão é apenas para navegação usando ng-click. No entanto, quando esse segundo botão é clicado, o AngularJS está causando uma atualização de página que aciona um 404. Soltei um ponto de interrupção na função e está acionando a minha função. Se eu fizer qualquer um dos seguintes, ele será interrompido:

  1. Se eu remover ng-click, o botão não causará uma atualização da página.
  2. Se eu comentar o código na função, ele não causará uma atualização da página.
  3. Se eu alterar a tag button para uma tag anchor ( <a>) com href="", isso não causará uma atualização.

A última parece ser a solução mais simples, mas por que o AngularJS está executando algum código após a minha função que faz com que a página seja recarregada? Parece um bug.

Aqui está o formulário:

<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>

Aqui está o método do controlador:

$scope.showChangePassword = function() {
  $scope.selectedLink = "changePassword";
};
chubbsondubs
fonte
Veja se esse é o seu problema github.com/angular/angular.js/issues/1238 (Infelizmente, não conheço o github o suficiente para saber se essa correção está na versão 1.0.1 ou não) .
precisa saber é o seguinte
Eu vi esse, mas não estou mudando o local, então acho que não se aplica. A menos que este outro botão esteja de alguma forma fazendo com que ele seja enviado, mas não seja definido como um tipo de envio, e quando tiro o ng-clique, o botão não envia o formulário.
Chubbsondubs
Seria ótimo se você pudesse fornecer uma demonstração funcional desse problema. Talvez começando com: Angular Plnkr
Pete BD

Respostas:

471

Se você der uma olhada na especificação do W3C , parece que o mais óbvio é tentar marcar os elementos do botão comtype='button' quando você não deseja que eles enviem.

O que deve ser observado em particular é onde diz

Um elemento de botão sem nenhum atributo de tipo especificado representa a mesma coisa que um elemento de botão com seu atributo de tipo definido como "enviar"

LOAS
fonte
4
Eu tenho o mesmo problema que OP, mas meus botões têm o tipo especificado - e ainda assim, clicar em causa a atualização. Algum outro lugar onde eu pudesse procurar?
Mateo Velenik 03/02
Isso sugere que seu problema está em javascript. O problema que minha resposta está abordando é mais uma questão entre o dom e o navegador. Alguns javascript que manipulam seu clique no botão provavelmente estão causando a recarga que você vê. Feliz caça;)
LOAS
Era exatamente isso que eu estava procurando. Foi muito chato na minha página porque era para mostrar apenas os erros e não enviar.
reaper_unique
Eu tenho meus botões marcados com type = "button" e também tenho o problema. No meu manipulador de ng-click, tenho $ event.stopPropagation (). Quando o removo, ele não é recarregado. Eu preciso disso. Alguma idéia de por que causa uma recarga de página ?!
Felixfbecker
@freshfelicio: tente adicionar também $event.preventDefault(), que ajudou no meu caso. Mas não tenho explicação porque: - \
Tim Büthe
72

Você pode tentar impedir o manipulador padrão:

html:

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

js:

$scope.saveUser = function (event) {
  event.preventDefault();
  // your code
}
antage
fonte
Agradável! Realmente buscou o meu cenário!
Richard
2
Isso funcionou para nós, ao usar o AngularJS dentro de um formulário do SharePoint. Eu tive que adicionar "event.stopPropagation ();" também.
Nick DeMayo 14/10
19

Você deve declarar o atributo ng-submit={expression}em seu<form> tag.

Nos documentos do ngSubmit, http://docs.angularjs.org/api/ng.directive:ngSubmit

Permite vincular expressões angulares para submeter eventos.

Além disso, evita a ação padrão (que, por forma, significa enviar a solicitação ao servidor e recarregar a página atual).

Shane Stillwell
fonte
3
Além disso, verifique se você não possui a propriedade 'action' configurada no formulário: form (action = "/ login", lng-submit = "login ()") Como isso fará com que a página seja atualizada mesmo que você tenha o conjunto ng-submit .
jenso
Enviando um formulário e impedindo a ação padrão Como a função dos formulários nos aplicativos Angular do lado do cliente é diferente da dos aplicativos de ida e volta clássicos, é desejável que o navegador não traduza o envio do formulário em um recarregamento de página inteira que envie os dados para o servidor . Em vez disso, alguma lógica javascript deve ser acionada para manipular o envio do formulário da maneira específica do aplicativo. Por esse motivo, Angular impede a ação padrão (envio de formulário ao servidor), a menos que o elemento <form> tenha um atributo de ação especificado. - docs.angularjs.org/api/ng.directive:form
Jignesh Gohel
Eu tenho um formulário com ng-submit = {expression} e um botão com o tipo = "submit". Funciona muito bem, exceto no BB10. Se eu usar o envio do teclado BB10, a página será atualizada. Se eu usar o botão que declarei no meu formulário, ele funcionará bem.
Michael
Isso não está funcionando para mim. Eu segui as instruções exatamente. A página ainda é
postada de
18

Eu uso a diretiva para impedir o comportamento padrão:

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

E então, em html:

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

Esta diretiva também pode ser usada com <a>e todas as outras tags

pleerock
fonte
+1 Obrigado! Isso é útil quando você não tem acesso à <form>tag e, portanto, não pode usar a ng-submitdiretiva.
jackvsworld
yow obrigado por esta, mas eu preciso também cancelar ng clique numa directiva
boi_echos
Isso também impede que o formulário ative o retorno de chamada ng-submit, certo?
Jhourlad Estrella
5

Você pode manter <button type="submit">, mas deve remover o atributo action=""de <form>.

Anderson Ferreira
fonte
2

Eu me pergunto por que ninguém propôs a solução possivelmente mais simples:

não use um <form>

A <whatever ng-form>IMHO faz um trabalho melhor e sem um formulário HTML, não há nada a ser enviado pelo próprio navegador. Qual é exatamente o comportamento certo ao usar o angular.

maaartinus
fonte
como aplicar o formvalid no clique, em seguida, sem tag de formulário?
Rizwan Patel
1
@RizwanPatel Acho que não entendo, mas com ng-form=someFormvocê consegue $scope.someForme tem um $validcampo. Então, eu tenho tudo o que preciso <button ng-disabled="!someForm.$valid">.
Maaartinus
1

Adicione ação ao seu formulário.

<form action="#">

Swapnil Patwa
fonte
1

Esta resposta pode não estar diretamente relacionada à pergunta. É apenas o caso quando você envia o formulário usando scripts.

De acordo com o código ng-submit

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

  event.preventDefault();
};

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

Ele adiciona o ouvinte de eventos de envio no formulário. Mas o manipulador de eventos de envio não seria chamado quando o envio for iniciado chamando form.submit (). Nesse caso, o ng-submit não impedirá a ação padrão; você deve chamar preventDefault você mesmo no manipulador do ng-submit;

Para fornecer uma resposta razoavelmente definitiva, o item 5 do Algoritmo de envio de formulários HTML declara que um formulário só envia um evento de envio se não tiver sido enviado chamando o método de envio (o que significa que ele só envia um evento de envio se enviado por um botão ou outro implícito pressionando enter enquanto o foco está em um elemento de texto do tipo de entrada).

Consulte O formulário enviado usando submit () de um link não pode ser capturado pelo manipulador de envio

user1577263
fonte
0

O primeiro botão envia o formulário e o segundo não

<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
fonte
0

Basta adicionar o arquivo FormsModulena importsmatriz app.module.tse adicionar import { FormsModule } from '@angular/forms';no topo deste arquivo ... isso funcionará.

Sahil Sharma
fonte