Form validation with Bootstrap 4 and AngularJS

4.3k Views Asked by At

I have a form made with Bootstrap 4 and AngularJS and I want to make a simple form validation where I could:

  1. validate input fields AFTER user has touched them,
  2. show two different error messages depending on validation constraint,
  3. create custom validation constraint (e.g. compare password and password confirmation field).

1.

In previous versions of Bootstrap you could do something like:

<div class="form-group" ng-class="{'has-error': userForm.email.$invalid && userForm.email.$touched}">

but with Bootstrap 4, there is no 'has-error' class. I tried to use 'is-invalid' class instead

<div class="form-group" ng-class="{'is-invalid': userForm.email.$invalid && userForm.email.$touched}">

but nothing happens. I managed to make it work as it is shown in Bootstrap 4 Documentation but validation happens only after the form submission and not when user has touched the input field.

2.

There are no error messages in Bootstrap 4, only 'invalid-feedback' and I can't figure out how to change message text depending on which constraint was violated. I tried something like:

<div class="invalid-feedback">
    <p ng-show="userForm.email.$error.required">Required</p>
    <p ng-show="userForm.email.$error.email">Enter a valid email</p>
</div>

but this does not work.

3.

I tried to make an Angular directive but because 1. and 2. didn't work I couldn't test this.

Any help will be appreciated.

UPDATE

As Peter Wilson suggested, nothing was wrong with my code. The code didn't work because my form was in a modal window and modal window must have a separate controller in AngularJS to be able to work correctly.

1

There are 1 best solutions below

2
Peter Wilson On BEST ANSWER

the is-invalid class is the right answer you may have another problem with your form so check my below demo

Note to test touched input you have to focus on the input and then leave focus to trigger touched state

angular.module('myApp',[])
.controller('myCtrl',function(){
  
})
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.js"></script>
<div ng-app="myApp" class="container">
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal">
  Launch demo modal
</button>

<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <div  ng-controller="myCtrl" class="container">
  <form name="loginForm" novalidate>
  <div class="form-group">
    <label for="exampleInputEmail1">Email address</label>
    <input type="email" ng-model="email"  required class="form-control" name="email" ng-class="{'is-invalid':loginForm.email.$error.required && loginForm.email.$touched}" placeholder="Enter email">
    <small ng-show="loginForm.email.$error.required && loginForm.email.$touched" id="emailHelp" class="form-text text-danger">email is required.</small>
  </div>

 
  <button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>

</div>