Angular: Empty Fiddle

http://angularjs.org/

by RoryOSiochain

HTML

<script src="http://code.angularjs.org/angular-1.0.1.js"></script>
<div ng-controller="appCtrl">
    <div ng-repeat="item in treeData">
        <treenode val="item"></treenode>
    </div>
    <div ng-repeat="item in treeData">
        <treenode val="item"></treenode>
    </div>
</div>

CSS

div {
    position: relative;
    margin-left: 20px;
}

JavaScript

angular.module('App', ['tree']);
angular.module('tree', [])
.directive('treenode', function ($compile) {
    return {
        restrict: 'E',
        scope: {
            val: '=',
            addChild: '&'
        },
        compile: function (tElement, tAttrs) {
            return function link(scope, element, attrs) {
                var inHTML;
                if (!scope.val.html) {
                    inHTML =
                        '<input ng-model="val.text" />' +
                        '<button ng-click="addChild()">+</button>' +
                        '<div ng-repeat="item in val.items"><treenode val="item"></treenode></div></span>';
                } else {
                    inHTML = scope.val.html;
                }
                $compile(inHTML)(scope.$new(), function (el, childscope) {
                    element.append(el);
                });
            }
        }
    }
})

.controller("appCtrl", ['$scope', function ($scope) {

    $scope.addChild = function (data) {
        console.log('Add Child!');
    };

    $scope.treeData = [{
        text: "First Parent Node",
        html: '<input ng-model="val.text" />' +
            '<div ng-repeat="item in val.items">' +
            '    <treenode val="item"></treenode>' +
            '</div>',
        items: [{
            text: "First Child Node",
            items: [{
                text: "First Grandchild Node",
                html: '<input ng-model="val.text" />'
            }]
        }, {
            text: "Second Child"
        }]
    }];
}]);