Подтвердить что ты не робот

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>
4b9b3361

Ответ 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"]);
            }
        }
    };
})