Giving the code inside of my controller:
$scope.entity = {
firstName: 'Jack',
lastName: 'Bauer',
location: {
city: 'New York'
}
};
$scope.path = 'location.city';
How do I dynamically bind ngModel
to the property of the entity
specified by path
?
I've tried something like this, but to no avail:
<input ng-model="'entity.' + path">
Giving the code inside of my controller:
$scope.entity = {
firstName: 'Jack',
lastName: 'Bauer',
location: {
city: 'New York'
}
};
$scope.path = 'location.city';
How do I dynamically bind ngModel
to the property of the entity
specified by path
?
I've tried something like this, but to no avail:
<input ng-model="'entity.' + path">
Share
Improve this question
asked Oct 15, 2015 at 16:27
Slava Fomin IISlava Fomin II
28.6k34 gold badges134 silver badges208 bronze badges
4 Answers
Reset to default 7Slava, I'm not too sure if this is a good idea to begin with. But anyhow,
You need to make your model getterSetter aware by adding this property to your input ng-model-options="{ getterSetter: true }
.
Then you need a function in your controller that builds a getterSetter out of a sting.
<input type="text" ng-model="propertify('entity.' + path)" ng-model-options="{ getterSetter: true }">
That's how the resulting template would look.
Luckily angular has an $parse service that makes this a lot easier. so something like this would need to be in your controller, or even better in a injected service.
$scope.propertify = function (string) {
var p = $parse(string);
var s = p.assign;
return function(newVal) {
if (newVal) {
s($scope,newVal);
}
return p($scope);
} ;
};
That will return a getter-setter function that handles this for you. see it in action in this plunk
Update
It's not working as expected, the value is displayed correctly, but can not be changed. The correct solution is provided by Sander here.
Incorrect solution
Wow, solved it accidentally:
<input type="text" ng-model="$eval('entity.' + path)">
And here's the Plunk.
I hope it will help someone.
You could use the bracket notation with a little modification, as you want to bind to a nested property. You have to split the path to the property:
<input ng-model="entity[locationKey][cityKey]"/>
Controller:
$scope.locationKey = 'location';
$scope.cityKey = 'city';
See js fiddle
After reading and using Sander Elias' answer, I was using this, but ran into another problem.
When combining his result with ng-required="true"
in the <input>
you could not empty the field, because when the field would be empty, the newVal
is passed as undefined
.
After some more research, I found an isssue on GitHub that addresses and solves this problem.
Here is what Sander's and the GitHub answer combined look like:
$scope.propertify = function (string) {
var property = $parse(string);
var propAssign = property.assign;
return function (newVal) {
if (arguments.length) {
newVal = angular.isDefined(newVal)? newVal : '';
propAssign($scope, newVal);
}
return property($scope);
};
};
The argument.length
reflects the number of values that are passed to the getter/setter and will be 0
on a get and 1
on a set.
Besided that, I added the angular.isDefined()
as Sumit suggested in a comment to also save false
and empty (""
) values.
Here is an updated Plunker