Angular: Empty Fiddle

http://angularjs.org/

by Pratik Bhattachary

HTML

<script src="http://code.angularjs.org/angular-1.0.1.js"></script>
<div ng-controller="CreateTreeController">
  <script type="text/ng-template" id="treeNode.html">
    <span>
			<input
				type="button"
				value="x"
				ng-click="remove(node,parent)"
			>
			<a href="#">{{node.title}}</a>, parent: {{parent.title}}
			<input 
				type="button" 
				value="+" 
				ng-click="addTo(node)"
			>
		</span>
    <div class="subNodes" ng-show="node.subNodes.length>0">
      <div class="node" ng-init="parent=oldParent;oldParent=node;" ng-repeat="node in node.subNodes" ng-include="'treeNode.html'"></div>
    </div>
  </script>

  <div class="node" ng-init="parent=tree;oldParent=parent[0];" ng-repeat="node in tree" ng-include="'treeNode.html'"></div>
</div>

CSS

{
  position: relative;
  box-sizing: border-box;
}

.node {
  padding: 1px 0;
}

.node>.subNodes {
  margin-left: 10px;
}

.node>.subNodes::before {
  content: '';
  display: block;
  width: 5px;
  height: 1px;
  background-color: black;
  position: absolute;
  top: 50%;
  left: -10px;
}

.node>.subNodes::after {
  content: '';
  display: block;
  width: 1px;
  height: 100%;
  background-color: black;
  position: absolute;
  top: 0;
  left: -5px;
  z-index: 1;
}

.node>.subNodes>.node::before {
  content: '';
  display: block;
  width: 5px;
  height: 1px;
  background-color: black;
  position: absolute;
  top: 50%;
  left: -5px;
  z-index: 3;
}

.node>.subNodes>.node:first-child::after {
  content: '';
  display: block;
  width: 1px;
  height: 50%;
  background-color: white;
  position: absolute;
  top: 0;
  left: -5px;
  z-index: 2;
}

.node>.subNodes>.node:last-child:not(:first-child)::after {
  content: '';
  display: block;
  width: 1px;
  height: calc(50% - 1px);
  background-color: white;
  position: absolute;
  bottom: 0;
  left: -5px;
  z-index: 2;
}

.node>.subNodes>.node:only-child::after {
  height: 100%;
}

.node>* {
  display: inline-block;
  vertical-align: middle;
}

.node [type=text] {
  width: 100px;
}

JavaScript

var myApp = angular.module('myApp', []);

//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});


myApp.controller('CreateTreeController', function($scope) {
  $scope.tree = [{
    title: 'node 1',
    subNodes: [{
      title: 'node 1.1',
      subNodes: []
    }, {
      title: 'node 1.2',
      subNodes: [{
        title: 'node 1.2.1',
        subNodes: []
      }, {
        title: 'node 1.2.2',
        subNodes: []
      }]
    }, {
      title: 'node 1.3',
      subNodes: []
    }]
  }];
  $scope.addTo = function(node) {
    node.subNodes.push({
      title: node.title + "." + (node.subNodes.length + 1),
      subNodes: []
    });
  }
  $scope.remove = function(node, parent) {
    var index = parent.subNodes.indexOf(node)
    if (index > -1) parent.subNodes.splice(index, 1);
  }
});