6

I'm building a form with AngularJS, and I noticed some behavior I don't understand.

When I assign ng-minlength=5 as an input attribute, AngularJS unbinds the value until it is longer than required.

This is inconvenient for me because I'd like to tell the user how much content they've entered using user.lifestory.length.

Why does AngularJS work this way? How can prevent Angular from unbinding the value while it's invalid?

<label for="lifeStory">Life story:<input name='lifeStory' type="text" ng-model='user.lifeStory' ng-minlength='5' required></input></label>

An example of this is here: http://jsfiddle.net/J67jm/3/

You can see the behavior I'm talking about by filling in the life story field.

1
  • does the same thing with email fields. Keeps the model null until valid. Not sure what workaround is Commented Jul 17, 2014 at 0:44

3 Answers 3

5

You can use {{myForm.lifeStory.$viewValue}} to get current viewValue of lifeStory (not bound to model yet). This is the sample code to solve your problem.

<span>Your life story needs to be at least 5 characters. You have entered {{myForm.lifeStory.$viewValue.length}} charaters.</span>

Refer to jsfiddle version - http://jsfiddle.net/J67jm/9/

Sign up to request clarification or add additional context in comments.

2 Comments

Cool, I didn't know about $viewValue--nice to see they have that property available.
@wulftone, there is a trick to use angularjs. you can always use console.log($scope) to check what kind of listener that they bind.
2

Angular seems to return a value of undefined when the minlength is invalid, but you can make your own validator directive:

var myApp = angular.module('myApp',[]);

function MyCtrl($scope) {
  $scope.user = {};
  $scope.user.name = "";
  $scope.user.lifeStory = "";
}

myApp.directive('myMinlength', function (){ 
  return {
    require: 'ngModel',
    link: function(scope, elem, attr, ngModel) {
      var minlength = parseInt(attr.myMinlength); // Just for Int's sake ;)

      ngModel.$parsers.unshift(function(value) {
        value = value || '';  // Prevent the value from being undefined
        var valid = value.length >= minlength;
        ngModel.$setValidity('myMinlength', valid);
        return value;  // return the value no matter what
      });
    }
  };
});

And use it like this:

<input name='lifeStory' type="text" ng-model='user.lifeStory' my-minlength='5' required></input>

Here's the updated jsfiddle

It turns out that ngRequired has the same behavior, and can be fixed in the same way. It may be like this for all the validators?

I'd also like to know why the Angular team chose to unset the property...

3 Comments

I think this post answer why - stackoverflow.com/questions/18676461/…
@hutingung I see their point. I suppose it's nice that directives are so easy to write, so we can create custom behavior as needed, for cases like this question.
yes. But I think better not to create directive for that purpose. It might create inconsistent behaviour that some directive bind invalid value and some not. So, I posted my answer to use $viewValue from form.
1

You could also write a custom validator directive to restore the $viewValue for you like this:

.directive('myParser', function () {
  return {
    restrict: 'A',
    require: 'ngModel',
    priority: 1, // force the postLink below to run after other directives
    link: function (scope, element, attrs, modelCtrl) {
      modelCtrl.$parsers.push(function (viewValue) {
        return (viewValue === undefined) ? modelCtrl.$viewValue : viewValue;
      });
    }
  }
});

and use it like this:

<input name="lifeStory" type="text" ng-model="user.lifeStory" ng-minlength="5" required my-parser></input>

Example plunker: http://plnkr.co/edit/LbhF865FS8Zq5bQnpxnz?p=preview

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.