How to use transclusion in the below case. The intention is to use markup in the html (partials) file, than defining it in template (within the directive).
I found a great tree directive here. (source) Original: http://jsfiddle.net/n8dPm/
Instead of defining the template in the directive, I was trying to use a transcluded content. I also updated Angular to 1.2.0.rc2. Updated: http://jsfiddle.net/aZx7B/2/
got below error
TypeError: Property '$transclude' of object [object Object] is not a function
code:
module.directive("tree", function($compile) {
    return {
        restrict: "E",
        transclude: true,
        scope: {family: '='},
        template:       
            '<ul>' + 
                '<li ng-transclude></li>' +
                '<li ng-repeat="child in family.children">' +
                    '<tree family="child"></tree>' +
                '</li>' +
            '</ul>',
        compile: function(tElement, tAttr) {
            var contents = tElement.contents().remove();
            var compiledContents;
            return function(scope, iElement, iAttr) {
                if(!compiledContents) {
                    compiledContents = $compile(contents);
                }
                compiledContents(scope, function(clone, scope) {
                         iElement.append(clone); 
                });
            };
        }
    };
});
<div ng-app="myapp">
    <div ng-controller="TreeCtrl">
        <tree family="family">
            <p>{{ family.name }}</p>
        </tree>
    </div>
</div>
With David's suggestion, made some changes. http://jsfiddle.net/aZx7B/3/
now, it prints, Parent. changing, family -> treeFamily didn't work though
The ng-transclude directive facilitates AngularJS to capture everything that is put inside the directive in the markup and use it somewhere in the directive's template.
The ng-transclude directive is used to mark the insertion point for transcluded DOM of the nearest parent that uses transclusion. Use transclusion slot name as the value of ng-transclude or ng-transclude-slot attribute.
transclude - compile the content of the element and make it available to the directive. Typically used with ngTransclude. The advantage of transclusion is that the linking function receives a transclusion function which is pre-bound to the correct scope.
The ng-app directive initializes an AngularJS application. The ng-init directive initializes application data. The ng-model directive binds the value of HTML controls (input, select, textarea) to application data.
You need to output the name of the family in the template as well: http://jsfiddle.net/roadprophet/DsvX6/
module.directive("tree", function($compile) {
    return {
        restrict: "E",
        transclude: true,
        scope: {family: '='},
        template:       
            '<ul>' + 
                '<li ng-transclude></li>' +
                '<li ng-repeat="child in family.children">' +
                    '<tree family="child">{{family.name}}</tree>' +
                '</li>' +
            '</ul>',
        compile: function(tElement, tAttr, transclude) {
            var contents = tElement.contents().remove();
            var compiledContents;
            return function(scope, iElement, iAttr) {
                if(!compiledContents) {
                    compiledContents = $compile(contents, transclude);
                }
                compiledContents(scope, function(clone, scope) {
                         iElement.append(clone); 
                });
            };
        }
    };
});
EDIT
You could also simplify by doing this: http://jsfiddle.net/roadprophet/DsvX6/2/
<div ng-app="myapp">
    <div ng-controller="TreeCtrl">
        <tree family="treeFamily">           
        </tree>
    </div>
</div>
module.directive("tree", function($compile) {
    return {
        restrict: "E",
        transclude: true,
        scope: {family: '='},
        template:       
            '<ul>' + 
                '<li ng-transclude></li>' +
                '<p>{{ family.name }}</p>' + 
                '<li ng-repeat="child in family.children">' +
                    '<tree family="child"></tree>' +
                '</li>' +
            '</ul>',
        compile: function(tElement, tAttr, transclude) {
            var contents = tElement.contents().remove();
            var compiledContents;
            return function(scope, iElement, iAttr) {
                if(!compiledContents) {
                    compiledContents = $compile(contents, transclude);
                }
                compiledContents(scope, function(clone, scope) {
                         iElement.append(clone); 
                });
            };
        }
    };
});
EDIT Same source of the problem though. No template being passed to the inner tree directive. http://jsfiddle.net/roadprophet/DsvX6/3/
<div ng-app="myapp">
    <div ng-controller="TreeCtrl">
        <tree family="treeFamily">           
                <p>{{ family.name }}</p>
        </tree>
    </div>
</div>
 template:       
            '<ul>' + 
                '<li ng-transclude></li>' +
                '<li ng-repeat="child in family.children">' +
                    '<tree family="child"><div ng-transclude></div></tree>' +
                '</li>' +
            '</ul>'
                        You want to compile the transcluded DOM against the parent scope; you can do this automatically with the injectable $transclude function in a directive's controller definition:
module.directive("tree", function($compile) {
  return {
    restrict: "E",
    transclude: true,
    scope: { family: '=' },
    template: '<ul>' + 
                '<li ng-repeat="child in family.children">' +
                  '<tree family="child">' +
                    '<p>{{ child.name }}</p>' +
                  '</tree>' +
                '</li>' +
              '</ul>',
    controller: function($element, $transclude) {
      $transclude(function(e) {
        $element.append(e);
      });
    },
    compile: function(tElement, tAttr, transclude) {
      var contents = tElement.contents().remove();
      var compiledContents;
      return function(scope, iElement, iAttr) {
        if(!compiledContents) {
          compiledContents = $compile(contents);
        }
        compiledContents(scope, function(clone) {
          iElement.append(clone);
        });
      };
    }
  };
});
This allows you to use the parent scope property treeFamily in your root template (also notice the use of child in the directive's template, above):
<div ng-app="myapp">
  <div ng-controller="TreeCtrl">
    <tree family="treeFamily">
      <p>{{ treeFamily.name }}</p>
    </tree>
  </div>
</div>
You can see an example here: http://jsfiddle.net/BinaryMuse/UzHeW/
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