Ng-maxlength закручивает мою модель
Я пытаюсь сделать простую текстовую область с "количеством оставшихся символов" вместе с проверкой.
когда я использую ng-maxlength для проверки моей формы, он сбрасывает мой charcount, как только длина достигает максимальной длины. Здесь plunkr Любые обходные пути?
<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
Когда ваше текстовое поле превышает 15 символов, result
становится undefined
— что как работают директивы ng-min/maxlength
. Думаю, вам придется написать свою собственную директиву. Вот директива, которая блокирует ввод после 15 символов:
<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
Обновить:, чтобы разрешить более 15 символов, но отключите кнопку отправки, если счетчик превышает 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
В качестве альтернативы вы можете просто добавить стандартный атрибут html maxlength
рядом с 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>
Это будет отключено с символами "15", поскольку maxlength
всегда выполнялся, и, кроме того, ng-maxlength
позволяет показывать пользовательское сообщение при достижении лимита.
Нажмите для примера Plunker
Ответ 3
Если вы добавляете атрибут name в текстовое поле, тогда новое свойство со значением создается в области формы, которую вы можете использовать для получения длины для вашего счетчика символов.
<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>
Обновлен plnkr
Ответ 4
Как показывает doc, функция $validate устанавливает модель на undefined, когда срок действия изменяется на недействительный.
Но мы все же можем предотвратить это поведение, просто добавив allowInvalid: true
в параметры ng-model.
Итак, просто измените свой код следующим образом:
<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
Я думаю, что это должно быть зарегистрировано как ошибка в angular. Он не должен очищать вашу модель. У меня есть директива, которая связывает выпадающий список в текстовом поле, и как только вы вставляете слово, которое заставляет его переходить на максимальную длину, тогда оно очищает мою модель и текстовое поле. Оно должно быть валидатором, не очистит вашу модель, если она думает, что модель недействительна.
Ответ 6
Альтернативой, которую я использую, является сохранение того же поведения, что и валидатор ng-maxlength, но для возврата длины через дополнительный атрибут "фактическая длина".
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);
}
};
});
Вот элемент с дополнительным атрибутом:
<textarea name="myTextarea" new-maxlength="100" actual-length="actualLength" ng-model="text"></textarea>
Ответ 7
У меня есть лучшее решение, я думаю: установить максимальную длину, если присутствует ng-maxlength.
Таким образом вы получаете обе функции одновременно: angular проверки + текст отключен
.directive("textarea", function () {
return {
restrict: "E",
link: function (scope, elem, attrs) {
if (angular.isDefined(attrs["ngMaxlength"])) {
attrs.$set("maxlength", attrs["ngMaxlength"]);
}
}
};
})