ng-maxlength screws up my model

ng-maxlength screws up my model

(https://stackoverflow.com/questions/17075969/ng-maxlength-screws-up-my-model)

I’m trying to do a simple textarea with “so many chars remaining” along with validation. when I use ng-maxlength to validate my form, it resets my charcount as soon as the length hits the max length. Here’s the plunkr Any workarounds?

1
2
3
4
5
6
7
<body ng-controller="MainCtrl">
<div ng-form="noteForm">
<textarea ng-maxlength="15" ng-model="result"></textarea>
<p>{{15 - result.length}} chars remaining</p>
<button ng-disabled="!noteForm.$valid">Submit</button>
</div>
</body>

Funny thing, but for me (using Angular 1.4.7 + TypeScript 1.8.7) usage of HTML attribute “maxLength” had same effect as for mentioned here “ng-maxLength”: after setting some big value (bigger than defined limit) directly into model, value in model becomes undefined. From my point of view, this is Angular bug (just like user3232182 mentioned above). Probably even not linked to ng-maxLength directve, but to the whole binding mechanism. – bkg Apr 20 ‘16 at 7:13


When your textarea exceeds 15 characters, result becomes undefined — that’s just how the ng-min/maxlength directives work. I think you’ll have to write your own directive. Here is a directive that will block input after 15 characters:

1
<textarea my-maxlength="15" ng-model="result"></textarea>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
app.directive('myMaxlength', function() {
return {
require: 'ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
var maxlength = Number(attrs.myMaxlength);
function fromUser(text) {
if (text.length > maxlength) {
var transformedInput = text.substring(0, maxlength);
ngModelCtrl.$setViewValue(transformedInput);
ngModelCtrl.$render();
return transformedInput;
}
return text;
}
ngModelCtrl.$parsers.push(fromUser);
}
};
});

When your textarea exceeds 15 characters, result becomes undefined — that’s just how the ng-min/maxlength directives work. I think you’ll have to write your own directive. Here is a directive that will block input after 15 characters:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<textarea my-maxlength="15" ng-model="result"></textarea>
app.directive('myMaxlength', function() {
return {
require: 'ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
var maxlength = Number(attrs.myMaxlength);
function fromUser(text) {
if (text.length > maxlength) {
var transformedInput = text.substring(0, maxlength);
ngModelCtrl.$setViewValue(transformedInput);
ngModelCtrl.$render();
return transformedInput;
}
return text;
}
ngModelCtrl.$parsers.push(fromUser);
}
};
});

Update: to allow more than 15 characters, but disable the submit button when the count exceeds 15:

1
2
3
4
5
6
7
8
link: function (scope, element, attrs, ngModelCtrl) {
var maxlength = Number(attrs.myMaxlength);
function fromUser(text) {
ngModelCtrl.$setValidity('unique', text.length <= maxlength);
return text;
}
ngModelCtrl.$parsers.push(fromUser);
}

As the doc says, the $validate function set model to undefined when validity changes to invalid.

But, we can still prevent this behavior simply by adding allowInvalid: true to the ng-model-options.

So, just modify your code like:

1
2
3
4
5
6
7
8
<body ng-controller="MainCtrl">
<div ng-form="noteForm">
<textarea ng-maxlength="15" ng-model="result"
ng-model-options="{ allowInvalid: true }"></textarea>
<p>{{15 - result.length}} chars remaining</p>
<button ng-disabled="!noteForm.$valid">Submit</button>
</div>
</body>