ngModel - 如何在不弄脏的情况下操纵初始模型值?

Pau*_*aul 4 angularjs angular-ngmodel

假设我想要一个指令,它接受用户在输入中键入的内容并将其转换为小写。

所以我想出了一个这样的指令(在这个 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'
  }
})
Run Code Online (Sandbox Code Playgroud)

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

此外,我想避免在用户实际与之交互之前将控件变为脏控件,因此即使我确实让它调用 $setViewValue 并导致 $parsers 管道,我也希望它意识到用户实际上并没有与之交互(因此保持它的原始状态)。

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

edr*_*ian 5

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

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

var tmp = ngModelController.$setDirty;
ngModelController.$setDirty = angular.noop;
ngModelController.$setViewValue(value);
ngModelController.$setDirty = tmp;
Run Code Online (Sandbox Code Playgroud)

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

当心:我没有使用自定义 ng-model-options。我没有尝试过,但我确定如果您使用自定义去抖动超时,则此解决方案对您不起作用,但我认为可以ngModelController.$setDirty = tmp;在去抖动时间到期后设法呼叫线路。