【问题标题】:ng-maxlength screws up my modelng-maxlength 搞砸了我的模型
【发布时间】:2013-06-09 04:24:10
【问题描述】:

我正在尝试使用“剩余这么多字符”以及验证来做一个简单的文本区域。 当我使用 ng-maxlength 验证我的表单时,只要长度达到最大长度,它就会重置我的字符数。这是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>

【问题讨论】:

  • 有趣的事情,但对我来说(使用 Angular 1.4.7 + TypeScript 1.8.7)HTML 属性“maxLength”的使用与这里提到的“ng-maxLength”具有相同的效果:设置一些大的值(大于定义的限制)直接进入模型,模型中的值变为未定义。从我的角度来看,这是 Angular 错误(就像上面提到的user3232182)。可能甚至没有链接到 ng-maxLength 指令,而是链接到整个绑定机制。

标签: angularjs ng-maxlength


【解决方案1】:

当您的 textarea 超过 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

【讨论】:

  • 非常感谢。我希望它超越并像推特一样显示负面,但这已经足够了:)
  • 太棒了!这应该是默认的 ng-maxlength 行为。也许你可以把它推到有角度的;)
  • @MarkRajcok 当我手动编辑输入时,此解决方案对我来说正常工作,但它没有捕获初始值的错误。添加 ngModelCtrl.$formatters.push(fromUser),就像默认的 Angular 验证器一样,修复它。
  • 不要使用 myMaxlength,因为如果您粘贴足够大的文本,它会再次调用自己 $setViewValue。最好使用验证。因此,我遇到了“超出最大调用堆栈大小”错误。
  • 如果您添加 ng-model-options="{allowInvalid: true}",您可以使用 ng-maxlength 实现此行为。来源:stackoverflow.com/a/29132765/592062
【解决方案2】:

或者,您可以在ng-maxlength 旁边添加标准html 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 允许您在达到限制时显示自定义消息。

Click for Plunker Example

【讨论】:

  • 我认为这是迄今为止最好的方法。
  • 这也包括粘贴大于最大值的文本,谢谢。
  • 是的,这就是我让它工作的方式,虽然效率不高,因为我需要在两个属性中重复相同的值......
  • 这是一种非常糟糕的方法,maxlength 属性非常糟糕——当我粘贴一些东西时它只会剪切文本——这对用户不友好。当我粘贴某些内容并出现溢出错误时,我想查看所有文本并决定删除哪些内容以适应最大长度。
  • 这是最简单也是最好的方法
【解决方案3】:

如果您向 textarea 添加一个 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

【讨论】:

  • 这个很好,不需要额外的代码。谢谢!
  • 为什么这个答案没有更多的赞成票。如此快速简单且切中要害。 :D 谢谢,是的,请
【解决方案4】:

正如doc 所说,当有效性变为无效时,$validate 函数将模型设置为未定义。

但是,我们仍然可以通过将allowInvalid: true 添加到 ng-model-options 来防止这种行为。

所以,只需修改您的代码,如下所示:

<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,则设置 maxlength。

        这样您可以同时获得两个功能:角度验证 + 文本截断

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

        【讨论】:

        • 确实如此。但我猜你可以在这种情况下使用 polyfills。找到的示例:stackoverflow.com/questions/1125482/…,虽然我没有尝试让它在指令中工作,但我想这并不难。感谢您的提示!
        猜你喜欢
        • 1970-01-01
        • 2018-04-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多