Why does ng-messages for form validation not work when using $rollbackViewValue

Issue

I have a form using ng-messages for form validation error messages. Im also using the new ng-model-options with $rollbackViewValue to rollback all changes to the form. Problem is ng-mesages will not work if I use the rollbackViewValue on the form.

I really like this new function in angular1.3 using ng-model-options to reset a form as I have not found anything that works as well as $rollbackViewValue()

Heres is the code and plunker

<!DOCTYPE html>
    <html data-ng-app="App">
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css"/>
    </head>
    <body>
    <div class="container" data-ng-controller="formCrtl as vm">
        <div class="col-lg-5">
        <form name="form" novalidate="novalidate" role="form"
              data-ng-submit="vm.submit()"
              data-ng-model-options="{updateOn: 'submit'}" >
            <!---->
            <div class="form-group"  data-ng-class="{ 'has-error': form.fname.$invalid && form.fname.$touched }">
                <label for="fname">First Name</label>
                <input type="text" required class="form-control" name="fname" id="fname" placeholder="Enter text" data-ng-model="vm.names.fname">
                <div data-ng-if="form.fname.$touched" data-ng-messages="form.fname.$error">
                    <span class="help-block" data-ng-message="required">required field</span>
                </div>
            </div>
            <div class="form-group" data-ng-class="{ 'has-error': form.lname.$invalid && form.lname.$touched }">
                <label for="lname">Last Name</label>
                <input type="text" required class="form-control" name="lname" id="lname" placeholder="Enter text" data-ng-model="vm.names.lname">
                <div data-ng-if="form.lname.$touched" data-ng-messages="form.lname.$error">
                    <span class="help-block" data-ng-message="required">required field</span>
                </div>
            </div>
            <div class="col-sm-offset-2 col-sm-10 btn-group">
                <button type="submit" class="btn btn-primary" data-ng-disabled="form.$invalid">Submit</button>
                <button type="button" class="btn btn-default" data-ng-click="form.$rollbackViewValue()">reset</button>
                <!---->
            </div>
        </form>
        </div>
    </div>


    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.8/angular.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.8/angular-messages.js"></script>
    <script src="scripts.js"></script>
    </body>
    </html>

controller

var App = angular.module("App", ['App', 'ngMessages']);
App.controller('formCrtl',function ($scope, $rootScope) {

    var vm = this;
    vm.names = {
        fname: "Albert",
        lname: "Capone"
    }
});

Solution

You would need to make the form pristine and revert back the touched state as well. You can do so by calling the special functions, $setPristine() and $setUntouched() , on the formController. But it appears rollBackViewValue works with ngSubmit, but it is only to revertback during some action, (like esc key, another button). But if the form field has contraint errors it appears it updated viewvalue to nullify the entered value. You could try this way by resetting to default field values.

In your view:-

 <button type="button" class="btn btn-default" 
     data-ng-click="vm.reset(form)">reset</button>

In your controller:-

 var vm = this;
  var defModel = {
    fname: "Albert",
    lname: "Capone"
  };

  vm.names = angular.copy(defModel);

  vm.reset = function(form) {
    form.$rollbackViewValue();
    form.$setPristine(); //Set pristine state
    form.$setUntouched(); //Set state from touched to untouched
    vm.names = angular.copy(defModel); //reset model
  }
var App = angular.module("App", ['App', 'ngMessages']);
App.controller('formCrtl', function($scope, $rootScope) {

  var vm = this;
  var defModel = {
    fname: "Albert",
    lname: "Capone"
  };

  vm.names = angular.copy(defModel);


  vm.reset = function(form) {
    form.$rollbackViewValue(); //Probably can be removed
    form.$setPristine();
    form.$setUntouched();
   
    vm.names = angular.copy(defModel);
     
  }
});
<div data-ng-app="App">

  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />

  <div class="container" data-ng-controller="formCrtl as vm">
    <div class="col-lg-5">
      <form name="form" novalidate="novalidate" role="form" data-ng-submit="vm.submit(form)" data-ng-model-options="{updateOn: 'submit'}">
        <!---->
        <div class="form-group" data-ng-class="{ 'has-error': form.fname.$invalid && form.fname.$touched }">
          <label for="fname">First Name</label>
          <input type="text" required class="form-control" name="fname" id="fname" placeholder="Enter text" data-ng-model="vm.names.fname">
          <div data-ng-if="form.fname.$touched" data-ng-messages="form.fname.$error">
            <span class="help-block" data-ng-message="required">required field</span>
          </div>
        </div>
        <div class="form-group" data-ng-class="{ 'has-error': form.lname.$invalid && form.lname.$touched }">
          <label for="lname">Last Name</label>
          <input type="text" required class="form-control" name="lname" id="lname" placeholder="Enter text" data-ng-model="vm.names.lname">
          <div data-ng-if="form.lname.$touched" data-ng-messages="form.lname.$error">
            <span class="help-block" data-ng-message="required">required field</span>
          </div>
        </div>
        <div class="col-sm-offset-2 col-sm-10 btn-group">
          <button type="submit" class="btn btn-primary" data-ng-disabled="form.$invalid">Submit</button>
          <button type="button" class="btn btn-default" data-ng-click="vm.reset(form)">reset</button>
          <!---->
        </div>
      </form>
    </div>
  </div>


  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.8/angular.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.8/angular-messages.js"></script>
</div>

Answered By – PSL

Answer Checked By – Cary Denson (AngularFixing Admin)

Leave a Reply

Your email address will not be published.