web-dev-qa-db-fra.com

ng-maxlength bousille mon modèle

J'essaie de faire une zone de texte simple avec "tant de caractères restants" ainsi que la validation. lorsque j'utilise ng-maxlength pour valider mon formulaire, il réinitialise mon compte dès que la longueur atteint la longueur maximale. Voici le plunkr Des solutions de contournement?

  <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>
35
Riz

Lorsque votre zone de texte dépasse 15 caractères, result devient undefined - c'est ainsi que le ng-min/maxlength les directives fonctionnent. Je pense que vous devrez rédiger votre propre directive. Voici une directive qui bloquera l'entrée après 15 caractères:

<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


Mise à jour: pour autoriser plus de 15 caractères, mais désactivez le bouton d'envoi lorsque le nombre dépasse 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

56
Mark Rajcok

Alternativement, vous pouvez simplement ajouter l'attribut html maxlength standard à côté de 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>

Cela coupera à "15" caractères, comme maxlength l'a toujours fait, et en plus ng-maxlength vous permet d'afficher un message personnalisé lorsque vous atteignez la limite.

Cliquez pour l'exemple Plunker

52
Thalis K.

Si vous ajoutez un attribut de nom à la zone de texte, une nouvelle propriété avec la valeur est créée dans la portée du formulaire, que vous pouvez utiliser pour obtenir la longueur de votre compteur de caractères.

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

Mis à jour votre plnkr

17
jlooooo

Comme le dit doc , la fonction $ validate définit le modèle sur undefined lorsque la validité passe à invalide.

Mais, nous pouvons toujours empêcher ce comportement simplement en ajoutant allowInvalid: true aux options ng-model.

Donc, modifiez simplement votre code comme:

<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>
14
Lutz

Je pense que cela devrait être enregistré comme un bug sur angular. Il n'est pas censé effacer votre modèle.J'ai une directive qui relie une liste déroulante à une zone de texte et dès que vous insérez un mot qui le fait dépasser la longueur maximale, puis il efface mon modèle et ma zone de texte. être un validateur ne pas effacer votre modèle quand il pense que le modèle n'est pas valide.

3
user3232182

Une alternative que j'utilise est de conserver le même comportement que le validateur ng-maxlength mais de renvoyer la longueur via un attribut supplémentaire '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);
            }
        };
    });

Voici l'élément avec l'attribut supplémentaire:

<textarea name="myTextarea" new-maxlength="100" actual-length="actualLength" ng-model="text"></textarea>
3
PenFold

J'ai une meilleure solution, je pense: pour régler la longueur maximale si la longueur maximale ng est présente.

De cette façon, vous obtenez les deux fonctionnalités en même temps: angular + texte coupé

.directive("textarea", function () {
    return {
        restrict: "E",
        link: function (scope, elem, attrs) {
            if (angular.isDefined(attrs["ngMaxlength"])) {
                attrs.$set("maxlength", attrs["ngMaxlength"]);
            }
        }
    };
})
0
Kat Lim Ruiz