I have nested model and I am trying to avoid vm.someObject.someChild.ChildOfChild.name type of situations. Is there a way to set the model for outer <div> so that I can instead do ChildOfChild.name or even name. In Silverlight this was called DataContext. I put "vm" on the $scope, but in html I would like to avoid having to type the full path to attribute.
For example:
<div>
{{someObject.Id}}
<div>
{{someObject.name.first}}
{{someObject.name.last}}
</div>
<div>
{{someObject.someChild.name.first}}
</div>
</div>
I would like to do something like this
<div datacontext = someObject>
{{Id}}
<div datacontext = name>
{{first}}
{{last}}
</div>
<div datacontext = someChild.name>
{{first}}
</div>
</div>
You can do this with a custom directive.
HTML:
<div ng-app="myApp" ng-controller="myCtrl as ctrl">
<div>
Access from deepObj: {{ctrl.deepObj.one.two.three.four}}
</div>
<div scope-context="ctrl.deepObj.one.two.three">
Access from third level: {{four}}
</div>
</div>
JS:
var myApp = angular.module('myApp', []);
var myCtrl = function() {
this.deepObj = {one: {two: {three: {four: "value"}}}};
};
myApp.directive('scopeContext', function () {
return {
restrict:'A',
scope: true,
link:function (scope, element, attrs) {
var scopeContext = scope.$eval(attrs.scopeContext);
angular.extend(scope, scopeContext);
}
};
});
See the documentation on $compile for information on what scope: true does.
Make sure you don't call the directive something like data-context as an attribute starting with data- has a special meaning in HTML5.
Here is the plunker: http://plnkr.co/edit/rMUQlaNsH8RTWiRrmohx?p=preview
Note that this can break two-way bindings for primitive values on the scope context. See this plunker for an example: http://plnkr.co/edit/lCuNMxVaLY4l4k5tzHAn?p=preview
Try ng-init, you'll have one more ., but it's better than the other answer I've seen proposed:
<div ng-init="x = foo.bar.baz">
{{x.id}}
{{x.name}}
</div>
BUT Be warned, doing this actually creates a value on your scope, so doing this with something like ng-model if you're reusing the same name, or in a repeater, will produce unexpected results.
What @rob suggests above is clever, and I've seen it suggested before. But there are issues, which he touches on, in part at least:
ng-model this way will not be at all intuitive. You'll have to use $parent.whatever or $parent.$parent.whatever depending on how may contexts deep you are.* For reference, views are $compiled more than you think: For every item in a repeater, whenever it's changed for example.
I feel like this question comes up frequently in StackOverflow, but I'm unable to find other similar questions ATM. ... regardless, if you look at the approaches above, and the warnings given about what the side effects will be, you should be able to discern it's probably not a good idea to do what you're trying to do just for the sake of readability.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With