问题
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?
<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>
回答1:
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:
<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);
}
};
});
fiddle
Update: to allow more than 15 characters, but disable the submit button when the count exceeds 15:
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);
}
fiddle
回答2:
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
回答3:
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
回答4:
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>
回答5:
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 .
回答6:
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>
回答7:
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"]);
}
}
};
})
来源:https://stackoverflow.com/questions/17075969/ng-maxlength-screws-up-my-model