Yousef
Yousef

Reputation: 906

Bind to attributes in prototypically inherited scope

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

Answers (3)

Michael Kang
Michael Kang

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

haimlit
haimlit

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

Nikolas
Nikolas

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

Related Questions