Skip to content

Instantly share code, notes, and snippets.

@icholy
Last active December 15, 2015 00:29
Show Gist options
  • Save icholy/5173203 to your computer and use it in GitHub Desktop.
Save icholy/5173203 to your computer and use it in GitHub Desktop.

Angular's built in router is lacking when you start trying to do nested layouts. When people bring this up as an issue, the common response is that you can use ngInclude to do whatever you want. The problem with that is that you're basically throwing away the $route functionality.

That's what I thought until I read Ben Nadel's Post. When you're defining your routes, you can use arbitrary properties and they will be available on $route.current

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

App.config(function ($routeProvider) {
    $routeProvider
      .when('/foo', { foo: 'bar' })
      .otherwise({ redirectTo: '/foo' });
});

App.run(function ($rootScope, $route) {
  $rootScope.$on('$routeChangeSuccess', function () {
    console.log($route.current && $route.current.foo);
  });
});

Ben also introduces the idea of an Action Path which map to your application's nested layout.

$routeProvider
  .when('/users',              { action: 'users.list' })
  .when('/users/:userId',      { action: 'user.index' })
  .when('/users/:userId/edit', { action: 'user.edit' })
  .otherwise({ redirectTo: '/users' });

The action is split up into the ActionPathArray: 'users.list'.split('.') => ['users', 'list']
It is available on the $rootScope and stays in sync with the url.

Lets implement it!

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

App.run(function ($rootScope, $route) {
  $rootScope.actionArray = [];
  $rootScope.$on('$routeChangeSuccess', function () {
    if ($route.current && $route.current.action) {
      $rootScope.actionArray = $root.current.action.split('.');
    }
  });
});

This by itself is already pretty usefull because we have access to actionArray in every scope. If you need to highlight the current selected item in your navbar, you can use ngClass like this

Action Path: 'foo.something.else'

<ul>
  <li ng-class="{ active: actionArray[0] == 'foo' }">
    <a href="#/foo">Foo</a>
  </li>
  <li ng-class="{ active: actionArray[0] == 'bar' }">
    <a href="#/bar">Bar</a>
  </li>
  <li ng-class="{ active: actionArray[0] == 'baz' }">
    <a href="#/baz">Baz</a>
  </li>
</ul>

Since actionArray[0] == 'foo' the first li will have the active class assigned to it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment