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 th
If you add a name attribute to the textarea then a new property with the value is created in the scope of the form, which you can use to get the length for your character counter.
<body ng-controller="MainCtrl">
<div ng-form="noteForm">
<textarea ng-maxlength="15" name="noteItem" ng-model="result"></textarea>
<p>{{15 - noteForm.noteItem.$viewValue.length}} chars remaining</p>
<button ng-disabled="!noteForm.$valid">Submit</button>
</div>
</body>
Updated your plnkr
I have a better solution I think: to set the maxlength if the ng-maxlength is present.
This way you get both features at the same time: angular validations + text cut off
.directive("textarea", function () {
return {
restrict: "E",
link: function (scope, elem, attrs) {
if (angular.isDefined(attrs["ngMaxlength"])) {
attrs.$set("maxlength", attrs["ngMaxlength"]);
}
}
};
})
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:
<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>
An alternative that I'm using is to retain the same behaviour as the ng-maxlength validator but to feed the length back via an extra attribute 'actual-length'.
app.directive('newMaxlength', function () {
return {
require: 'ngModel',
scope: {
maxlength: '=newMaxlength',
actualLength: '='
},
link: function (scope, elem, attr, ngModelCtrl) {
function validate(ctrl, validatorName, validity, value) {
ctrl.$setValidity(validatorName, validity);
return validity ? value : undefined;
}
var maxlength = parseInt(scope.maxlength, 10);
var maxLengthValidator = function (value) {
scope.actualLength = value ? value.length : 0;
return validate(ngModelCtrl, 'maxlength', ngModelCtrl.$isEmpty(value) || value.length <= maxlength, value);
};
ngModelCtrl.$parsers.push(maxLengthValidator);
ngModelCtrl.$formatters.push(maxLengthValidator);
}
};
});
Here is the element with the extra attribute:
<textarea name="myTextarea" new-maxlength="100" actual-length="actualLength" ng-model="text"></textarea>
I think this should be logged as a bug on angular. It is not supposed to clear your model.I have a directive that links a dropdown select to a textbox and as soon as you insert a word that makes it go over the max-length then it clears my model and textbox.It is supposed to be a validator not clear your model when it thinks the model is invalid .
Alternatively you can just add the standard html maxlength
attribute alongside the ng-maxlength
.
<form name="myForm">
<textarea name="myTextarea" ng-maxlength="15" maxlength="15" ng-model="result"></textarea>
<span class="error" ng-show="myForm.myTextarea.$error.maxlength">
Reached limit!
</span>
</form>
This will cut-off at "15" characters, as maxlength
has always done, and additionally the ng-maxlength
lets you show custom message upon reaching the limit.
Click for Plunker Example