Reputation: 828
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?
Upvotes: 5
Views: 3260
Reputation: 2475
You can evaluate your model function dynamically, e.g.
<input type="text" ng-model="myModel(var)">
And in the controller:
$scope.myModel = function(var) {
return function(newValue) {
// this is a regular model function but you can use 'var' here
...
}
}
Upvotes: 0
Reputation: 878
ES5 Object properties to the rescue:
Object.defineProperty($scope, 'balance', {
enumberable: true,
get: function () {
// -- call your getter here
},
set: function (val) {
// -- call the setter here
}
});
This is native Javascript, so it does not get faster than this.
Upvotes: 0
Reputation: 4477
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 />
Upvotes: 3
Reputation: 49590
ngModel
supports getter and setters. Here's how it works:
<input ng-model="balance" ng-model-options="{ getterSetter: true }">
This works if balance
is a getter/setter function:
$scope.balance(100); // sets 100
var b = $scope.balance(); // returns 100
You don't need to expose each variable on the scope - you could just expose the Model
service that you use in your example:
$scope.Model = Model;
then, in the View, bind to whatever property you need:
<input ng-model="Model.balance" ng-model-options="{ getterSetter: true }">
Upvotes: 1
Reputation: 5964
Have all your variables in an object array:
[
{key: "Variable 1", value: 1, kind: "number"},
{key: "Variable 2", value: "some text", kind: "text"},
{key: "Variable 3", value: new Date(), kind: "date"}
]
Then in your view you shall create them with the help of an ng-repeat:
<div ng-repeat="variable in myVariables">
<input type="{{variable.kind}}" ng-model="variable.value" ng-change="changed(variable)">
</div>
If you need to update your external service, implement a method changed(variable) in your controller.
Upvotes: 0
Reputation: 116
look at example, i created for you. I hope I have understood you correctly
$scope.$watch('variables', function(newValue) {
console.log("triggers on variables change");
angular.forEach(newValue, function(value, key) {
Model.setValue(key, value);
});
}, true);
Upvotes: 1
Reputation: 29999
You can create a new directive which implements this behaviour.
<input model-getter='getFn()' model-setter='setFn($value)' />
This would be fairly straightforward to implement:
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 });
});
}
};
})
Upvotes: 1