179

I have my form like this:

<form name="myForm">
    <input name="myText" type="text" ng-model="mytext" required />
    <button disabled="{{ myForm.$invalid }}">Save</button>
</form>

As you may see, the button is disabled if the input is empty but it doesn't change back to enabled when it contains text. How can I make it work?

Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
ali
  • 10,927
  • 20
  • 89
  • 138

6 Answers6

351

You need to use the name of your form, as well as ng-disabled: Here's a demo on Plunker

<form name="myForm">
    <input name="myText" type="text" ng-model="mytext" required />
    <button ng-disabled="myForm.$invalid">Save</button>
</form>
Ben Lesh
  • 107,825
  • 47
  • 247
  • 232
  • Sorry, I use it now. Yet, it is still disabled even when the textbox contains text – ali Mar 08 '13 at 17:44
  • 1
    +1 Coincidentally, I was just reading this great post of yours: http://www.benlesh.com/2012/11/angular-js-form-validation.html – Ben May 15 '14 at 17:48
  • what if I don't have a form? Can I do that also on div element? – VsMaX Nov 13 '14 at 10:15
  • 1
    @MichaelCwienczek technically, you can add ng-form to a div tag: `
    ... stuff here ..
    `. Although, if you're submitting a value from inputs, on button push, I *highly* recommend using a `
    ` tag, if for no other reason than it allows a user to hit [ENTER] and submit the form. But it also likely constitutes better practice because of things like accessibility concerns.
    – Ben Lesh Nov 13 '14 at 20:14
  • 2
    @BenLesh, what if the submit button is not inside my form and still I have to disable it if the form in invalid. – Green Wizard Mar 14 '16 at 13:39
  • Your input element on plunker has 2 name attributes. ` – Nico Van Belle Jul 26 '17 at 08:55
34

To add to this answer. I just found out that it will also break down if you use a hyphen in your form name (Angular 1.3):

So this will not work:

<form name="my-form">
    <input name="myText" type="text" ng-model="mytext" required />
    <button ng-disabled="my-form.$invalid">Save</button>
</form>
wvdz
  • 16,251
  • 4
  • 53
  • 90
  • 3
    Yes, the form name should be in camel case for any AngularJS form validations. – dubilla Nov 04 '14 at 19:02
  • 7
    as a rule of thumb, all js like expressions will recognise objects in the camelcase form, while dash is for html like syntax – ecoologic Dec 15 '14 at 02:03
  • So, what happens if the form is a member of a formset, and therefore is required to have a name w/ a hyphen in it (like "my_formset_name-0")? – trubliphone Oct 07 '15 at 04:08
  • 2
    In the example above, I believe `myForm.$invalid` should still work, so in your case, I would think `my_formset_name0.$invalid` should work. – wvdz Oct 07 '15 at 20:39
29

Selected response is correct, but someone like me, may have issues with async validation with sending request to the server-side - button will be not disabled during given request processing, so button will blink, which looks pretty strange for the users.

To void this, you just need to handle $pending state of the form:

<form name="myForm">
  <input name="myText" type="text" ng-model="mytext" required />
  <button ng-disabled="myForm.$invalid || myForm.$pending">Save</button>
</form>
Ivan Sokalskiy
  • 812
  • 7
  • 14
6

If you are using Reactive Forms you can use this:

<button [disabled]="!contactForm.valid" type="submit" class="btn btn-lg btn primary" (click)="printSomething()">Submit</button>
Nelul
  • 115
  • 1
  • 8
  • 3
    Although this is valid advice for "Angular", this answer is invalid for "AngularJS". Namely, `(click)` and `[disabled]` aren't valid AngularJS code, nor are Reactive Forms a part of the AngularJS framework. _"Angular is the name for the Angular of today and tomorrow. AngularJS is the name for all v1.x versions of Angular"_ https://angular.io/guide/ajs-quick-reference – dapperdan1985 Oct 18 '18 at 23:22
2

<form name="myForm">
        <input name="myText" type="text" ng-model="mytext" required/>
        <button ng-disabled="myForm.$pristine|| myForm.$invalid">Save</button>
</form>

If you want to be a bit more strict

Cengkuru Michael
  • 4,590
  • 1
  • 33
  • 33
1

We can create a simple directive and disable the button until all the mandatory fields are filled.

angular.module('sampleapp').directive('disableBtn',
function() {
 return {
  restrict : 'A',
  link : function(scope, element, attrs) {
   var $el = $(element);
   var submitBtn = $el.find('button[type="submit"]');
   var _name = attrs.name;
   scope.$watch(_name + '.$valid', function(val) {
    if (val) {
     submitBtn.removeAttr('disabled');
    } else {
     submitBtn.attr('disabled', 'disabled');
    }
   });
  }
 };
}
);

For More Info click here

Prashobh
  • 9,216
  • 15
  • 61
  • 91
  • Your method of solution works for me with little tweak. Thank you – Tatipaka Jun 09 '16 at 13:00
  • Why would you do this when there are native directives `ng-disabled` in angular 1.x and `[disabled]` in angular 2|4.x that are much better tested than this?. Secondly, why have a directive that is scoped to a form to disable a nested button, it's super specific. An ill thought out solution IMO. – David Barker Nov 01 '17 at 07:27
  • Above is a sample directive , original have many scenarios like nested check box etc and I dont want to messy my html code by adding in every form,instead this directive will take care all the things. – Prashobh Nov 01 '17 at 11:10