Angular ng-model 动态 getter 和 setter

Angular ng-model dynamic getters and setters

我想将 ng-model 与外部模型服务一起使用。该模型有两个方法:getValue(variable) 和 setValue(variable)。

所以在我的 html 中,我希望能够做到:

<input type="text" ng-model="balance">

Note: balance is not defined on $scope in my controller. And because we are dealing with more then 4000 different variables, I don't want to define them all on $scope.

然后在更改时它必须调用模型的 setValue() 方法。所以在我的控制器中我想有这样的东西:

$catchAllGetter = function(variable) { // e.g. variable = 'balance'
     var value = Model.getValue(variable);
     return value;
}

$catchAllSetter = function(variable, value) { // called on change
     Model.setValue(variable, value);
}

Angular 可以实现这样的功能吗?

您可以创建一个实现此行为的新指令。

<input model-getter='getFn()' model-setter='setFn($value)' />

这将很容易实现:

app.directive('modelGetter', function() {
  return {
    restrict: 'A',
    scope: {
      get: '&modelGetter',
      set: '&modelSetter'
    },
    link: function(scope, element) {
      element.val(scope.get());
      element.on('change', function() {
        var val = element.val();
        scope.set({ $value: val });
      });
    }
  };
})

看看example,我为你创造的。希望我理解正确

$scope.$watch('variables', function(newValue) {
  console.log("triggers on variables change");
  angular.forEach(newValue, function(value, key) {
    Model.setValue(key, value);
  });  
}, true);

我的方法和@Dan Prince类似,但是实现有点不同

创建一个接受模型变量名称的指令,然后在指令本身中注入您的模型服务以执行获取和设置。

Edit : As specified by @Werlang, writing an attribute that replaces ngModel will refrain you from features like validation, formatting, debounced update, ng-change etc. So instead of writing a replacement, we will instead wire up a supplementary attribute

    app.directive('dynamicInput', function() {
      return {
        restrict: 'A',
        link: function(scope, el, attr) {
              scope.variableName = angular.copy(attr.ngModel); // Saving the variable name

              scope[attr.ngModel] = (attr.ngModel + '_1'); // Setting a dummy value in the scope variable.
              // In your case it will look something like scope[attr.ngModel] = Model.getValue(attr.ngModel);

                scope.$watch(attr.ngModel, function(newValue, oldValue) {

                  console.log(scope.variableName + " ==> " + newValue);

                  //Model.setValue(scope.variableName, newValue);

              });

        }
      };
    })

然后在你的 HTML 中:

    <input ng-model='balance' dynamic-input />

将所有变量放在一个对象数组中:

[
  {key: "Variable 1", value: 1, kind: "number"},
  {key: "Variable 2", value: "some text", kind: "text"},
  {key: "Variable 3", value: new Date(), kind: "date"}
]

然后在您看来,您将在 ng-repeat 的帮助下创建它们:

<div ng-repeat="variable in myVariables">
    <input type="{{variable.kind}}" ng-model="variable.value" ng-change="changed(variable)">
</div>

如果您需要更新您的外部服务,请在您的控制器中实现一个方法 changed(variable)。

ngModel 支持 getter 和设置器。它是这样工作的:

<input ng-model="balance" ng-model-options="{ getterSetter: true }">

如果 balance 是一个 getter/setter 函数,这有效:

$scope.balance(100);      // sets 100
var b = $scope.balance(); // returns 100

您不需要公开作用域上的每个变量 - 您可以只公开您在示例中使用的 Model 服务:

$scope.Model = Model;

然后,在视图中,绑定到您需要的任何 属性:

<input ng-model="Model.balance" ng-model-options="{ getterSetter: true }">

ES5 对象属性来拯救:

Object.defineProperty($scope, 'balance', {
  enumberable: true,
  get: function () {
    // -- call your getter here
  },
  set: function (val) {
    // -- call the setter here
  }
});

这是本机 Javascript,因此没有比这更快的了。

您可以动态评估您的模型功能,例如

<input type="text" ng-model="myModel(var)">

在控制器中:

$scope.myModel = function(var) {
  return function(newValue) {
     // this is a regular model function but you can use 'var' here
     ...
  }
}