0

I have two directives one is a 'fancy display' on a calculation from the parent - they are nested because sometimes the child is a child and sometimes it is independent.

<parent>
    <reuse data="{values: {one:parentobject.data.one, two:parentobject.data.two}}" />
    <label>{{parenobject.data.one}}</label><label>{{parentobject.data.two}}</label>
</parent>

<reuse>
   <label>{{Calculation}}</label>
</reuse>

directive

app.directive('reuse', [function(){
   var link = function(scope, elem, attrs){
      scope.Calculation = [perform calculation stuffs here];
   }
   var directive = {
      template: 'template.htm',
      scope:{
          data : '='
      },
      link:link
   }

   return directive;


}])

Everything works fine on the initial load - but my 'child' directive is not updating when the parent directives scope updates. All of the values in the parent scope and its display are updating but the child is not.

1 Answer 1

1

There are several problems with your code:

1) Since the child directive (reuse) defines isolate scope, it loses access to all values in the parent scope (such as parentoneobject) that are not explicitly passed through to the directive

2) Directives are not singletons, the second use of your directive, which prints out Calculation, has not received any parameters, and has no concept of what data is.

3) Inline HTML in a directive does not work unless transclusion is set up

http://plnkr.co/edit/HEMoes9nQEYjkm10Ghok?p=preview

The above plunker demonstrates the problem. Note that the labels referencing the parent from the child DO NOT POPULATE as parentobject changes, only those whose ng-model binds to the isolate scope get modified. Additionally, note that the two directives are COMPLETELY DISTINCT IN BOTH SCOPE AND DOM ELEMENT.

Now with that in mind, lets talk about how to make it work, with the following assumption:

1) Your inner directive's html may vary, and so can not be hardcoded to a template 2) The calculation needs to be displayed in different places with different scopes.

The first thing to do in this case is to add. a transclude: true flag to your directive. This will tell your directive to put in any nested HTML. This provides you with two options. The first is to use the ng-transclude attribute on your template to interpolate where you want such as:

template: "<div ng-transclude></div>

The problem with this approach is that the resulting scope will be a child scope of the upper scope, rather then the isolate scope, thus denying you the ability to access data, and calculation.

The second is to use the transclude function passed to the link function:

link: function(scope, elem, attrs, controller, transcludeFn){

This has the benefit of allowing you to massage the DOM as you see fit, and insert it yourself.In this case

transcludeFn(scope, function(clone, outerScope){
  elem.append(compile(clone)(scope));
});

Please note that clone is a copy of the original DOM e.g

</br><label>In child: {{data.values.one}}</label>
</br><label>In child: {{data.values.two}}</label>

This compiles the elements in the directive's isolate scope, rather then the parent's scope, before appending them to the directive's DOM.

Finally, the question arises how to share this data between different scopes. It is useful to remember, that in Angular, services are singletons shared across all scopes. So we create a service to conduct the calculation, bind to a calculation object by reference in our directive's scope (to avoid having to watch values and refetch), and voila!

This plunker shows how to tie the solution together:

http://plnkr.co/edit/JGoawYyNnwOyP4DZdg5z?p=preview

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.