Search code examples
javascriptangularjsangular-ngmodel

Angular ng-model dynamic getters and setters


I want to use ng-model with an external model-service. This model has two methods: getValue(variable) and setValue(variable).

So in my html I want to be able to do:

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

And then on change it must call the setValue() method of the model. So in my controller I would like to have something like:

$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);
}

Is something like this possible with Angular?


Solution

  • My approach is similar to @Dan Prince, but the implementation differs a bit

    Create a directive, that accepts name of the model variable, and then inject your model service in the directive itself to perform the getting and setting.

    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);
    
                  });
    
            }
          };
        })
    

    Then in your HTML :

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