231

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";
};
Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
chubbsondubs
  • 37,646
  • 24
  • 106
  • 138
  • See if this is your issue https://github.com/angular/angular.js/issues/1238 (Unfortunately, I don't know my way around github enough to be able to tell if this fix is in the 1.0.1 release or not). – Mark Rajcok Sep 07 '12 at 19:36
  • I saw that one, but I'm not changing the location so I don't think it applies. Unless this other button is somehow causing it to submit, but it's not defined as a submit type, and when I take off the ng-click the button doesn't submit the form. – chubbsondubs Sep 07 '12 at 23:26
  • It would be great it you could provide a working demo of this problem. Perhaps starting with: [Angular Plnkr](http://plnkr.co/edit/gist:3662656) – Pete BD Oct 05 '12 at 10:14
  • Dupe of http://stackoverflow.com/questions/932653/how-to-prevent-buttons-from-submitting-forms – Roy Truelove Aug 19 '13 at 16:54
  • Seem like duplicate. http://stackoverflow.com/questions/16703215/how-to-reload-or-re-render-the-entire-page-using-angularjs/34841811#34841811 – Vaibs Jan 17 '16 at 18:13
  • More like the link you listed is the dup. Check the dates. This predates that link. – chubbsondubs Jan 18 '16 at 16:02

11 Answers11

498

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"

Community
  • 1
  • 1
LOAS
  • 7,161
  • 2
  • 28
  • 25
  • 5
    I have the same problem as OP but my buttons have the type specified - and still click causes refresh. Any other places where I could look? – Mateo Velenik Feb 03 '15 at 11:55
  • That suggests to me that your problem is in javascript. The problem my answer is addressing is more a matter between the dom and the browser. Some javascript handling your button click is likely causing the reload you see. Happy hunting ;) – LOAS Feb 04 '15 at 12:47
  • This is exactly what I was looking for. It was very annoying on my page because it was supposed to only show the errors and not submit. – reaper_unique Mar 17 '15 at 10:10
  • I have my buttons marked with type="button" and have the issue too. In my ng-click handler, I have $event.stopPropagation(). When I remove it, it doesnt reload. I need it though. Any ideas why it causes a page reload?! – felixfbecker Aug 12 '15 at 15:36
  • @freshfelicio: try to also add `$event.preventDefault()`, that helped in my case. But I have no explaination why :-\ – Tim Büthe Sep 11 '15 at 10:59
75

You can try to prevent default handler:

html:

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

js:

$scope.saveUser = function (event) {
  event.preventDefault();
  // your code
}
antage
  • 1,100
  • 7
  • 11
19

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

Shane Stillwell
  • 3,198
  • 5
  • 31
  • 53
  • 3
    Also, make sure you dont have 'action' property set on the form: form(action="/login", lng-submit="login()") Since this will make the page refresh even if you have ng-submit set. – james Mar 06 '13 at 16:03
  • Submitting a form and preventing default action Since the role of forms in client-side Angular applications is different than in classical roundtrip apps, it is desirable for the browser not to translate the form submission into a full page reload that sends the data to the server. Instead some javascript logic should be triggered to handle the form submission in application specific way. For this reason, Angular prevents the default action (form submission to the server) unless the
    element has an action attribute specified. - http://docs.angularjs.org/api/ng.directive:form
    – Jignesh Gohel Mar 22 '13 at 13:34
  • I have a form with ng-submit={expression} and a button with type="submit". Works like just fine except on BB10. If I use BB10 keyboard's Submit then the page will refresh. If I use the button which I've declared in my form it work fine. – Michael Nov 11 '13 at 17:05
  • This isnt working for me. I followed the directions exactly. The page still posts back – Northstrider Feb 13 '15 at 16:21
18

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

pleerock
  • 18,322
  • 16
  • 103
  • 128
5

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

2

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.

xKobalt
  • 1,498
  • 2
  • 13
  • 19
Fahim khan
  • 31
  • 1
1

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.

maaartinus
  • 44,714
  • 32
  • 161
  • 320
1

Add action to your form.

<form action="#">

Swapnil Patwa
  • 4,069
  • 3
  • 25
  • 37
1

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

user1577263
  • 449
  • 5
  • 8
0

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>
Amay Kulkarni
  • 828
  • 13
  • 16
0

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.

Sahil Sharma
  • 136
  • 1
  • 8