2

I want to set a field of a particular form as dirty as I am manually changing that value.I have already gone the the SO thread Angular.js programmatically setting a form field to dirty , But no luck.

Here is the sample replica of my issue. Plunk

<html ng-app="sampleApp">

<head>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0- rc.4/angular.min.js"></script>
 <style type="text/css">
 input.ng-invalid {
  border: 1px solid red;
 }
input.ng-valid {
  border: 1px solid green;
}
input.ng-pristine {
  border-color: #FFFF00;
}
</style>
<script type="text/javascript">
 var sampleApp = angular.module("sampleApp", []);
 sampleApp.controller('sampleCtrl', ['$scope', '$http', '$timeout',
   function($scope, $http, $timeout) {
     $scope.userData = {
       username: "",
     };

     $timeout(function() {
       $scope.userData.username = '$#deepak';
     }, 5000);

   }
 ]);
 sampleApp.directive('myUsername', [
   function() {
     // Runs during compile
     return {

       require: 'ngModel', // Array = multiple requires, ? = optional, ^ = check parent 
       link: function($scope, iElm, iAttrs, controller) {

         controller.$parsers.unshift(function(value) {
           //allow only alphanumeric characters
           var reg = /^\w+$/;
           var isValidUsername = reg.test(value);
           controller.$setValidity('username', isValidUsername);

           return isValidUsername ? value : undefined;
         });

         controller.$formatters.unshift(function(value) {
           var reg = /^\w+$/;
           var isValidUsername = reg.test(value);

           controller.$setValidity('username', isValidUsername);
          $scop  e.registrationForm.username.$setViewValue($scope.registrationForm.username.$viewValue);
           return value;
         })

       }
     };
   }
 ]);
  </script>
  </head>

 <body ng-controller="sampleCtrl">
  <div ng-show="bShowStatus">
   {{message}}
   <ul ng-repeat="err in errors">
     {{err}}
   </ul>
  </div>
  <form name="registrationForm" ng-submit="submitForm()" novalidate>
    UserName
    <br>
    <input type="text" name="username" ng-model="userData.username" ng-model-options="{updateOn:  'blur'}" my-username>&nbsp;&nbsp;
    <span ng-show="registrationForm.username.$dirty && registrationForm.username.$error.username">
            Invalid Username.
        </span>

 <br>
 <br>
 <input type="submit" value="Submit">
 </form>
</body>

</html>

In the sample I am modifying the username after 5 second (only for the example). At the same time , I want to set the field as dirty and fire the validation and show the error message.

Please help.

Community
  • 1
  • 1
Deepak Kumar Padhy
  • 4,128
  • 6
  • 43
  • 79
  • I've been looking into this as well and older versions of angular used a method involving setting the value of the relevant ngModel property to it's own current value... this would trigger the dirty flag. Unfortunately this no longer appears to work in 1.3+ – Hades Nov 30 '14 at 12:19

2 Answers2

1

Deepak

Here is the plnkr with the solution http://plnkr.co/edit/69Beli?p=preview. Instead of updating the $scope.userData.username directly and bypassing the parser pipeline of 'model to view', use jQuery to update the input field and trigger the 'change' event and use the 'view to model' pipeline provided by Angular.

            $timeout(function(){
              jQuery("[name=username]").val('$#deepak');
              jQuery("[name=username]").trigger('change');
            }, 5000);

Another plnkr http://plnkr.co/edit/Zct92r with $render implemented. This is for 'model to view' pipeline, $render is invoked after $parser and setting the styles based on errors.

    controller.$render = function() {
      console.log('in render');
      iAttrs.$set('value', controller.$viewValue);
      if (controller.$invalid && controller.$viewValue.length !== 0) {
        iElm.css("border", "1px solid red");
      } else if (controller.$viewValue.length === 0) {
        iElm.css("border", "1px solid gold");
      } else {
        iElm.css("border", "1px solid green");
      }
    };

Both solution feels like a hack and $render feels more so. Whatever is set in $render, has to be compensated in $parser and undone.

user2176745
  • 491
  • 4
  • 11
0

Well, it works for me using the $dirty flag discussed in the thread (Angular.js programmatically setting a form field to dirty):

$timeout(function(){
    $scope.userData.username = '$#deepak';
    $scope.registrationForm.username.$dirty = true;
}, 5000);

See working plunker here: http://plnkr.co/edit/ZvX62jJsklPLyw7Q4nlT?p=preview

Community
  • 1
  • 1
pacog
  • 119
  • 1
  • 5