【问题标题】:ngModel - how to manipulate initial model value without making it dirty?ngModel - 如何操纵初始模型值而不使其变脏?
【发布时间】:2015-08-12 20:37:45
【问题描述】:

假设我想要一个指令,它将用户输入的内容转换为小写。

所以我想出了这样的指令(在这个 Plunker http://plnkr.co/edit/jnE3s8MRr1tFCX0WVYel?p=preview 中):

app.directive('lowerCaseInput', function() {
  return {
    restrict: 'E',
    template:'<input ng-model="vm.input" />',
    scope: {},
    require: ['ngModel', 'lowerCaseInput'],
    controller:function() {},
    link: function(scope, el, attrs, ctrls) {
      var ngModel = ctrls[0], vm = ctrls[1];
      ngModel.$render = render;

        // view-> model
      ngModel.$parsers.push(function(value) {
        return toLowerCase(value);
      });

        // model->view
      ngModel.$formatters.push(function(value) {
        return value;
      });

      function render() {
        vm.input = ngModel.$viewValue;
      }

      // view -> model && model-> view
      function toLowerCase(value) {
        return value && value.toLowerCase();
      }

      scope.$watch('vm.input', function(newVal, oldVal) {
        if(newVal !== oldVal)
          ngModel.$setViewValue(newVal);
        });
    },
    controllerAs: 'vm'
  }
})

但是,正如您在演示中看到的那样,模型值不会在初始传递时得到反映(变为全小写),因为从未触发 setViewValue。对于我确实希望指令根据某些规则更改模型的情况,我应该遵循一种通用方法吗?

此外,在用户实际与之交互之前,我希望避免将控件变为脏,所以即使我确实让它调用 $setViewValue 并导致 $parsers 管道,我希望它实现用户实际上并没有与它交互(因此保持它 $pristine)。

这可能吗?如果是这样,关于它的一些最佳实践是什么(比如可以从 $format 调用 $setViewValue -- 直接覆盖 ngModel 吗?等等......

【问题讨论】:

    标签: angularjs angular-ngmodel


    【解决方案1】:

    以下解决方案适用于我(使用 Angular 1.4)

    在更新 viewvalue y 之前,只需保存对 $setDirty 函数的引用,并在 ngModelCtrl 中将其替换为空函数。设置 viewvalue 后,我恢复了原始功能。

    var tmp = ngModelController.$setDirty;
    ngModelController.$setDirty = angular.noop;
    ngModelController.$setViewValue(value);
    ngModelController.$setDirty = tmp;
    

    这对我有用,因为我可以在自定义指令中设置默认值,并且输入字段和表单控制器都保持 $pristine。

    注意:我没有使用自定义 ng-model-options。我没有尝试过,但我确信如果您使用自定义去抖超时,此解决方案将不适合您,但我认为可以在去抖时间到期后调用ngModelController.$setDirty = tmp; 行。

    【讨论】:

    • 每日黑客攻击!这是唯一按预期工作的答案。在 $setViewValue 上有一个抑制脏污的标志会很好。
    • 这是最极客的答案!
    • 这让我很开心!
    【解决方案2】:

    这是你需要的指令。

    app.directive('lowerCaseInput', function() {
      function toLowerCase(value) {
        return value && value.toLowerCase();
      }
    
      return {
        restrict: 'E',
        template: '<input ng-model="getterSetter" ng-model-options="{getterSetter : true}">',
        scope: {
          ngModel: '='
        },
        controller: function($scope) {
          $scope.getterSetter = function(value) {
            return $scope.ngModel = toLowerCase(value || $scope.ngModel);;
          }
        }
      }
    })
    

    检查 Plunker here 和 文档here

    【讨论】:

      【解决方案3】:

      查看this plunk

      app.directive('lowerCaseInput', function() {
        return {
          restrict: 'A', // as attribute to 'decorate' normal input
          require: 'ngModel',
          link: function(scope, el, attrs, ngModel) {
            // view-> model
            ngModel.$parsers.push(toLowerCase);
            // model->view
            ngModel.$formatters.push(toLowerCase);
            
            function toLowerCase(value) {
              return value && value.toLowerCase();
            }
          
            // if input value should reflect modelValue
            el.on('blur', function () {
              if (ngModel.$viewValue !== ngModel.$modelValue) {
                ngModel.$setViewValue(ngModel.$modelValue);
                ngModel.$render();
              }
            });
          }
        }
      })
      

      首先:您的解决方案过于复杂,因为您创建了两个 ngModel 实例,而您可以轻松“装饰”普通文本输入。在您的实现中,您将所有逻辑分配给指令元素上的 ngModel,而不是模板输入的 ngModel。

      我的解决方案不需要在链接阶段操作 ngModel,因为这项工作留给了 $formatters。但如果您真的需要在不创建 ngModel $dirty 的情况下操作模型值,您可以执行以下操作:

      var isPristine = ngModel.$pristine;
      ngModel.$setViewValue(something);
      if (isPristine) { ngModel.$setPristine(); }
      

      编辑:

      我的解决方案正确设置了$viewValue,但在$modelValue 下仍然保持不正确的值。 更正确解决方案is here,但它远非“ok”IMO。

      【讨论】:

      • 谢谢——但这仍然存在原始模型值保持大写直到你模糊它的问题——并且即使用户实际上并没有改变任何东西也会使它变脏(触摸可能应该设置——但不脏?)
      • 对不起,我的错误。我现在想不出更好的than this
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-26
      • 2017-12-27
      • 2019-10-15
      • 2021-06-12
      • 2019-11-10
      相关资源
      最近更新 更多