Advanced form control with AngularJS and Bootstrap3

PDF

Forms in angular are pretty straightforward once you know how to read its state. So let’s look at a collection of tricks and put together and complete working Bootstrap 3 form with fabulous form validation.

In this form:

  1. No validation while initially filling the form
  2. On submit: validate form and keep updating fields as they change
  3. Red and green colors indicate the user’s progress
  4. Once submitted invalid form, the submit button becomes available only once the form is valid
  5. Bootstrap 3 form style, including help text and custom tailored alerts for validation messages

What AngularJS gives you

With AngularJS, <form> is actually a built in directive that keeps track of the form’s validity status. It has features such as $pristine vs $dirty (did the user interact with the form or not), $valid vs $invalid and so on. Furthermore, it provides specific validations on input-basis. All of this information is available out of the box on the scope using expressions as you would normally. A form’s scope is available under the name of the form. So let’s take a look at a login form:

This form immediately displays validation errors even prior to submitting and the button is disabled while the form is in an invalid state.

Now this approach may satisfy your requirements, but this means you need to start showing form validation errors as soon as the form is visible, because you can’t submit the form until it is filled in correctly; not the best way to engage the user:

“Hey I need some information for you! Hey, I know you didn’t fill in anything, but everything is filled in wrong!”

Also notice we put in a novalidate to circumvent the browsers built in validation capabilities, since we want to let AngularJS and our own code to take care of that. (I wouldn’t assign a value to novalidate normally, but this code prettify plugin goes crazy otherwise).

On submit, validate form before sending request

One thing is missing is a flag that indicates if the form has been submitted. Often what you want to do is only show validation errors once the form has been submitted and then in runtime keep the user updated about his input fixes (still wrong or now it’s good). So there’s a small trick for that:

Now in your form you can use this scope variable to only show validation errors when submitted is true (for example ng-show="submitted && form.email.$error.required"). A better example can be found on jsfiddle.

However, this does not help us much, because the form is still being submitted since we put in the novalidate attribute (the browser is not preventing a submit). So we need to prevent the form from submitting itself and we do that by introducing a directive that cooperates with the built in <form> directive.

This directive blocks the form from actually submitting until all validations are green. Original credits go to malix (I think), for providing the proof of concept, which I refined for personal use.

Now to use this!

Note that form validations are ignored if you don’t actually bind on a scope with ng-model!

 

So this is basically all you need, but we can go further. We can make green what was filled in incorrectly and corrected by the user. Finally we can put some Bootstrap 3 sauce on top of this!

Let’s just cut to the chase:

Final solution in Bootstrap 3

Pristine pre-submit state: no errors, button enabled

Invalid post-submit state: errors/successes shown runtime, submit button disabled

final solution in jsFiddle

Tags:
  • Marcel

    Nice! This saved me a lot of time…

    Reply

  • robbie

    gooood 🙂

    Reply

  • Norman Klein

    Shouldn’t the Submit button be disabled until the required fields are filled out? Also the required fields need to have a visual distinction (different border color or red field color or even a red asterisk as on this HTML page). Otherwise the user is compelled to press Submit to discover this info (resulting in an unnecessary click).

    But this is still the best form validation I’ve yet seen for AngularJS + Bootstrap

    Reply

    • Benny Bottema Post author

      That’s a possible optimization, sure! It depends on preference I guess. Personally I like the form to be as passive and non-intrusive until absolutely necessary.

      Reply

  • Jake

    This was great and very helpful. I have a question about this line in the directive:

    fn(scope, { $event : event });

    I understand that it processes the submission handler function, however, I don’t know what the $event: event represents.

    Reply

    • Benny Bottema Post author

      It’s simply being passed on as the submission handler normally would have access to this event data. In this example however it is not used.

      Reply

  • Jake

    So I’m trying to do a watch in another directive on the form.$submitted property, but it doesn’t watch it properly:

    angular.module('myApp')
    .directive 'validateInput', [ () ->
    require: '^form',
    link: (scope, elem, attrs, ctrl) ->
    parentDiv = $(elem).parent().closest('div')

    scope.$watch 'ctrl.$submitted', () ->
    console.log(ctrl)
    if ctrl.$submitted && theInputIsValid (haven't added this in yet)
    parentDiv.attr("class", 'has-success')
    else
    parentDiv.attr("class", 'has-error')
    alertDiv = 'This field is required'
    $(alertDiv).insertAfter(elem).parent()
    , true
    ]

    Sorry it’s in coffee script. This directive is placed on input fields within the form. I’m trying to automate adding the ng-class and alert divs that you have in this example, but have been banging my head on a wall for the past 3 days. Anyway, just thought I’d throw this out there for anyone else interested

    Reply

Leave a Reply