Clicking a button within a form causes page refresh

The question:

I have a form in Angular that has two buttons tags in it. One button submits the form on ng-click. The other button is purely for navigation using ng-click. However, when this second button is clicked, AngularJS is causing a page refresh which triggers a 404. I’ve dropped a breakpoint in the function and it is triggering my function. If I do any of the following, it stops:

  1. If I remove the ng-click, the button doesn’t cause a page refresh.
  2. If I comment out the code in the function, it doesn’t cause a page refresh.
  3. If I change the button tag to an anchor tag (<a>) with href="", then it doesn’t cause a refresh.

The latter seems like the simplest workaround, but why is AngularJS even running any code after my function that causes the page to reload? Seems like a bug.

Here is the form:

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

Here is the controller method:

$scope.showChangePassword = function() {
  $scope.selectedLink = "changePassword";
};

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

If you have a look at the W3C specification, it would seem like the obvious thing to try is to mark your button elements with type='button' when you don’t want them to submit.

The thing to note in particular is where it says

A button element with no type attribute specified represents the same thing as a button element with its type attribute set to “submit”

Method 2

You can try to prevent default handler:

html:

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

js:

$scope.saveUser = function (event) {
  event.preventDefault();
  // your code
}

Method 3

You should declare the attribute ng-submit={expression} in your <form> tag.

From the ngSubmit docs
http://docs.angularjs.org/api/ng.directive:ngSubmit

Enables binding angular expressions to onsubmit events.

Additionally it prevents the default action (which for form means sending the request to the server and reloading the current page).

Method 4

I use directive to prevent default behaviour:

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

And then, in html:

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

This directive can also be used with <a> and all other tags

Method 5

You can keep <button type="submit">, but must remove the attribute action="" of <form>.

Method 6

I wonder why nobody proposed the possibly simplest solution:

don’t use a <form>

A <whatever ng-form> does IMHO a better job and without an HTML form, there’s nothing to be submitted by the browser itself. Which is exactly the right behavior when using angular.

Method 7

Add action to your form.

<form action="#">

Method 8

This answer may not be directly related to the question. It’s just for the case when you submit the form using scripts.

According to ng-submit code

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

  event.preventDefault();
};

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

It adds submit event listener on the form.
But submit event handler wouldn’t be called when submit is initiated by calling form.submit(). In this case, ng-submit will not prevent the default action, you have to call preventDefault yourself in ng-submit handler;

To provide a reasonably definitive answer, the HTML Form Submission Algorithm item 5 states that a form only dispatches a submit event if it was not submitted by calling the submit method (which means it only dispatches a submit event if submitted by a button or other implicit method, e.g. pressing enter while focus is on an input type text element).

See Form submitted using submit() from a link cannot be caught by onsubmit handler

Method 9

First Button submits the form and second does not

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

Method 10

Just add the FormsModule in the imports array of app.module.ts file,
and add import { FormsModule } from '@angular/forms'; at the top of this file…this will work.

Method 11

I also had the same problem, but gladelly I fixed this by changing the type like from type="submit" to type="button" and it worked.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment