<html> <head> <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.js"></script> <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.1/js/jquery.dataTables.min.js"></script> <link href="http://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.1/css/jquery.dataTables.css" rel="stylesheet" type="text/css" /> <link href="http://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.1/css/jquery.dataTables_themeroller.css" rel="stylesheet" type="text/css" /> </head> <style> .panelHeader { background-color:#094661; color:white; } .panelHeader h2 { margin:0; } .outerPanel { border:solid 1px #094661; border-radius:5px; } </style> <script> //create module var myApp = angular.module ("myApp", []); myApp.controller ('PageController', function ($scope) { console.log ("Welcome to PageController, scope.$id is:" + $scope.$id); $scope.calc=function () { return 1000; } }); //directive var directive = myApp.directive ('panel', function ($compile) { return { scope:{ styleForPanel:"@" }, transclude: false, //replace:true, restrict:"E", compile:function (element,attrs) { console.log ("Welcome to panel::compile, id=" + element.attr ('id')); //find header //important, pick up only the one we need var panelHeader = element.find ("panel-header")[0]; //create new DOM //we do not use transclusion and therefore angular will bind variables from this template to //parent scope - NOT the isolated scope as we need var div=angular.element ('<div data-ng-style="styleForPanel" class="outerPanel"></div>').append (panelHeader); div.append ("<hr />"); div.append (element.html ()); element.replaceWith (div); return function link ($scope, $element, $attrs, controllers, transclude){ //support panel style console.log ("panel link directive called for id:" + $attrs ['id']); $($element).css ('cssText', $scope.styleForPanel) } } }; }); var directive = myApp.directive ('panelHeader', function () { return { scope:{ }, replace:true, restrict:"E", template:'<div><div class="panelHeader"><div data-ng-transclude></div></div></div>', transclude:true, link:function ($scope, $element, $attrs){ console.log ("panelHeader link directive called for id:" + $element.attr ('id')); } }; }); </script> <body data-ng-app="myApp" data-ng-controller="PageController"> <panel id="panel_1"> <panel-header id="panel_header_1"> <h2>Panel Header:{{1 + 3}}</h2> </panel-header> <panel id="panel_2" data-style-for-panel="margin-left:200px; margin-top:50px; margin-bottom:20px;"> <panel-header id="panel_header_2"> <h2>Nested Panel</h2> </panel-header> Nested Panel Body </panel> <panel id="panel_3" data-style-for-panel="margin-left:400px; margin-top:15px; margin-bottom:40px;"> <panel-header id="panel_header_3"> <h2>Another Nested Panel</h2> </panel-header> Another Nested Panel Body: {{calc () * 245.1}} </panel> Panel Body: {{56 + 1234}} <br /> Calc from controller:{{calc ()}} <br /> <panel id="panel_4" data-style-for-panel="margin-left:20px; margin-top:10px; margin-bottom:10px;"> <panel-header id="panel_header_4"> <h2>Yet Another Nested Panel</h2> </panel-header> Yet Another Nested Panel Body: {{calc () * 24}} </panel> </panel> </body> </html>