arrow-left arrow-right brightness-2 chevron-left chevron-right circle-half-full dots-horizontal facebook-box facebook loader magnify menu-down RSS star Twitter twitter GitHub white-balance-sunny window-close
Angular.js: Layouts and Sections
2 min read

Angular.js: Layouts and Sections

This is an old post and doesn't necessarily reflect my current thinking on a topic, and some links or images may not work. The text is preserved here for posterity.

I've been building out the new UI for Octopus 2.0 in Angular.js, which has been a fun process and something I hope to blog more about later.

Angular layouts/master pages and sections

Coming from an ASP.NET MVC background, one of the concepts I found myself missing was that of "sections". A solution I came up with was to use two custom directives:

  • octo-placeholder designates an area on the parent layout where content will be placed
  • octo-section designates content that will be added to the parent layout

My layout page looks like this (simplified):

<... snip ...>
<body>
  <div class='top'>
    <div class='tools' octo-placeholder='tools'></div>

    <div class='breadcrumbs' octo-placeholder='breadcrumbs'></div>
  </div>

  <ng-view></ng-view>
</body>

My view looks like this:

<script octo-section="breadcrumbs" type="text/ng-template" >
  <p>This is the breadcrumbs area {{ someVariable }}</p>
</script>

<script octo-section="tools" type="text/ng-template" >
  <a ng-show="loaded">Hello</a>
</script>

<p>This is the main content</p>

The directives that make this all work are:

.directive("octoPlaceholder", function(octoUtil, $compile, $route, $rootScope) {
  return { 
    restrict: 'AC',
    link: function(scope, element, attr) {
      // Store the placeholder element for later use
      $rootScope["placeholder_" + attr.octoPlaceholder] = element[0];

      // Clear the placeholder when navigating
      $rootScope.$on('$routeChangeSuccess', function(e, a, b) {
        element.html('');
      });
    }
  };
})

.directive("octoSection", function(octoUtil, $compile, $route, $rootScope) {
  return {
    restrict: 'AC',
    link: function(scope, element, attr) {
      // Locate the placeholder element
      var targetElement = $rootScope["placeholder_" + attr.octoSection];

      // Compile the template and bind it to the current scope, and inject it into the placeholder
      $(targetElement).html($compile(element.html())(scope));
    }
  };
})

Unlike solutions that use ng-include, the directives use the current view's scope rather than creating a new scope. This means that you can use bindings within the sections without a problem.

Hopefully this helps someone else!

Enjoying these posts? Subscribe for more

Subscribe now
Already have an account? Sign in
Paul Stovell's Blog

Hello, I'm Paul Stovell

I'm a Brisbane-based software developer, and founder of Octopus Deploy, a DevOps automation software company. This is my personal blog where I write about my journey with Octopus and software development.

I write new blog posts about once a month. Subscribe and I'll send you an email when I publish something new.

Subscribe

Comments

You've successfully subscribed to Paul Stovell's Blog.
Success! Your account is fully activated, you now have access to all content.
Success! Your billing info is updated.