angular.module("app", []).controller('app', function ($log, $scope) {
    $scope.layout = 'vertical';

    $scope.toggle = function () {
        if ($scope.layout === 'vertical') {
            $scope.layout = 'horizontal';
        } else {
            $scope.layout = 'vertical';
        }
    };

}).directive("layout", function ($log, $parse) {


    var link = function (scope, concreteElement, concreteAttributes, transcludeFN) {
        var direction = $parse(concreteAttributes.layout);

        var width = function (e) {
            return Math.floor(e.outerWidth(true)) || 0;
        };
        var height = function (e) {
            return Math.floor(e.outerHeight(true)) || 0;
        };

        var wrapper = concreteElement.find(".wrapper");
        var nw = null;
        var ctr = null;
        var se = null;

        var verticalOrientation = true;

        var doLayout = function () {
            nw.css("left", "0px").css("top", "0px").css("bottom", "").css("right", "");
            se.css("bottom", "0px").css("right", "0px").css("left", "").css("top", "");
            ctr.css("left", "").css("right", "").css("bottom", "").css("top", "");

            verticalOrientation = direction(scope) === 'vertical';

            if (verticalOrientation) {
                nw.css("right", "0px");
                ctr.css("left", "0px").css("right", "0px");
                se.css("left", "0px");
                ctr.css("top", height(nw) + "px");
                ctr.css("bottom", height(se) + "px");

            } else {
                nw.css("bottom", "0px");
                ctr.css("top", "0px").css("bottom", "0px");
                se.css("top", "0px");
                ctr.css("left", width(nw) + "px");
                ctr.css("right", width(se) + "px");
            }

        };






        // transclude the contents of the element and associate the parent scope with the 
        // transcluded elements
        // the clone parameter is actually the set of nodes directly below the node with the directive, and 
        // each of the nodes has been compiled and linked already.
        // in thise case, we're going to use the scope's parent scope to for the linking
        transcludeFN(scope.$parent, function (clone) {

            nw = $(clone.filter(".position-north, .position-west").get(0));
            ctr = $(clone.filter(".position-center").get(0));
            se = $(clone.filter(".position-south, .position-east").get(0));

            nw.css("position", "absolute");
            ctr.css("position", "absolute");
            se.css("position", "absolute");

            // choose the right set of nodes from all those that have been cloned, compiled, and linked
            // we need to append to the concreteElement, because it might be different from the templateElement
            // when inside a ng-repeat (lots of examples get this wrong)
            wrapper.append(nw);
            wrapper.append(ctr);
            wrapper.append(se);
        });


        scope.$watch(function () {
            return width(nw);
        }, doLayout);
        scope.$watch(function () {
            return height(nw);
        }, doLayout);
        scope.$watch(function () {
            return width(se);
        }, doLayout);
        scope.$watch(function () {
            return height(se);
        }, doLayout);
        scope.$watch(function () {
            return width(wrapper);
        }, doLayout);
        scope.$watch(function () {
            return height(wrapper);
        }, doLayout);
        scope.$watch(direction,
        doLayout);
    };

    var compile = function (templateElement, templateAttributes, transcludeFN) {

        // here, you can modify the templateElement and templateAttributes;

        // the compile function returns the linking function; we're going to "transclude"
        // in the linking function and not in the compile function
        return function (scope, concreteElement, concreteAttributes) {
            link(scope, concreteElement, concreteAttributes, transcludeFN);
        };
    };

    return {
        // it's probably good practice to ALWAYS introduce a scope when transcluding and using scope.$parent
        // when applying the transclusion function
        scope: true,
        restrict: 'A',
        compile: compile,
        transclude: true,

        // use replace to swap out the node that has this directive with the node generated by the template;
        // this isn't really necessary
        template: "<div class='wrapper' style='width: 100%; height: 100%; position: relative'></div"
    };
});
<!DOCTYPE html>
<html ng-app="app">
  
  <head>
    <meta charset="utf-8">
    <title>AngularJS Template</title>
    <script>
      document.write('<base href="' + document.location + '" />');
    </script>
    <link rel="stylesheet" href="style.css">
    <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
    <script src="http://code.angularjs.org/1.1.4/angular.js"></script>
    <script src="app.js"></script>
  </head>
  
  <body><div ng-controller='app' style='height: 100%' ng-click='toggle()'>
    <!-- for testing, i've added a repeater, because if you're using the wrong element for linking it'll become apparent -->
    <div layout="layout">
        <!-- south and east are the same component -->
        <div class='position-south'><span ng-show='layout==="vertical"'>South</span><span ng-hide='layout==="vertical"'>East</span>

        </div>
        <!-- north and west are the same component -->
        <div class='position-north'><span ng-show='layout==="vertical"'>North</span><span ng-hide='layout==="vertical"'>West</span>

        </div>
        <div class='position-center'>Center</div>
    </div>
</div></body>

</html>
html, body, [layout] {
    height: 100%;
    width: 100%;
}
.wrapper {
    background-color: red;
}
.position-north, .position-west {
    background-color : blue;
}
.position-south, .position-east {
    background-color: green;
}
.position-center {
    background-color: yellow;
}