Reputation: 906
I'd like to create a directive, with a prototypically inherited scope (i.e. scope=true), but also set up scope binding to attributes, similar to following when setting up an isolated scope:
scope = {
'varname':'=attrname'
}
My current solution is to set scope=true and set up the binding to the attributes along the following lines in the link function:
scope.$watch(element.attr('attrname'), function(val) { scope.varname = val; }); // watch changes scope.varname = scope.$eval(element.attr('attrname')); // initialize
Although it does the trick it doesn't seem to be very elegant. What approach do you suggest?
I find it surprising angularjs seems to expect that in a directive you wouldn't need attribute binding when setting up a new inherited scope.
Upvotes: 5
Views: 614
Reputation: 52847
I know what you mean and I agree with you. It would be nice if Angular provided a convenient framework for a directive to set-up two-way model binding between a parent scope variable and a child scope variable and still support prototypical scope inheritance.
To achieve the same effect as the following with isolated scope:
scope = {'varname':'=attrname'}
you can set up the two-way model binding within your directive's link function:
scope: true,
link: function(scope, element, attr) {
// when attrname changes in parent scope, update varname in current scope
scope.$parent.$watch(attr.attrname, function(newVal) {
scope.varname = newVal;
});
// when varname changes in current scope, update attrname in parent scope
scope.$watch('varname', function(newVal) {
scope.$parent[attr.attrname] = newVal;
});
}
Upvotes: 1
Reputation: 2582
I think what you're looking for is this code in the directive link function:
var yourVar = $parse(attrs.attrName)(scope); // Parse the attribute with a specific scope context
You'll then pass attributes like you did with isolated scope directive, while still being able to use a prototypically inherited scope.
If you find yourself wanting to observe the changes of the variable, then I believe that you should use isolated scope and not inherited. It's still doable by observing attribute changes like suggested below, however I don't think it's the best practice. (I don't have much to support that claim, only intuition, so pick whatever you think is best)
If you want to know how $parse works, you can find more info here: https://docs.angularjs.org/api/ng/service/$parse
Please let me know in the comments if you need a plunker also, or if you got the hang of it.
Upvotes: 0
Reputation: 1176
Given what you want to achieve I consider your solution totaly valid. You could still improve your code if you use $scope.$observe()
instead of $scope.$watch()
:
scope.$observe('attrname', function(val) {
scope.varname = $parse(val)(scope);
});
Upvotes: 0