Skip to content

Instantly share code, notes, and snippets.

@davisford
Created November 20, 2012 18:54
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save davisford/4120142 to your computer and use it in GitHub Desktop.
Save davisford/4120142 to your computer and use it in GitHub Desktop.
Flexible Angular Routing + Twitter Bootstrap - composite Views
extends layout
block content
// navbar
div.navbar.navbar-fixed(ng-controller="NavCtrl")
div.navbar-inner
div.container
a.btn.btn-navbar(data-toggle="collapse", data-target=".nav-collapse")
span.icon-bar
a.brand(href="home")
img#logo(src="/images/logo.png")
div.nav-collapse
ul.nav.top-menu
li(ng-class="navClass('home')")
a(href="home", ng-class="{ on: isHome }") Home
li(ng-class="navClass('devices')")
a(href="devices", ng-class="{ on: isDevices }") Devices
li(ng-class="navClass('tracking')")
a(href="tracking", ng-class="{ on: isTracking }") Tracking
li(ng-class="navClass('alerts')")
a(href="alerts", ng-class="{ on: isAlerts }") Alerts
// fluid container
div.container-fluid#content(ng-switch="renderPath[0]")
div(ng-switch-when="home")
p home
div(ng-switch-when="split")
div.span3
div.well.sidebar-nav
ul.nav.nav-list
li.nav-header Select a device
div.span9(ng-switch="renderPath[1]")
div(ng-switch-when="devices")
p Devices
div(ng-switch-when="tracking")
p Tracking
div(ng-switch-when="alerts")
p alerts
angular.module('myApp', ['ssAngular'])
.config(function ($routeProvider, $locationProvider) {
$routeProvider
.when("/home", { action: "home.view" })
.when("/devices", { action: "devices.view" });
$locationProvider.html5Mode(true);
})
.controller('AppCtrl', function($scope, $route, $routeParams) {
render = function () {
var renderAction = $route.current.action,
renderPath = renderAction.split(".");
$scope.renderAction = renderAction;
$scope.renderPath = renderPath;
$scope.isHome = (renderPath[0] == "home");
$scope.isDevices = (renderPath[0] == "devices");
}
$scope.$on("$routeChangeSuccess",
function ($currentRoute, $previousRoute) {
render();
});
})
.controller('HomeCtrl', function ($scope) {
// etc
})
.controller('DeviceCtrl', function ($scope) {
// etc.
});
/*global angular:false */
angular.module('myApp', ['ssAngular']).config(function($routeProvider, $locationProvider) {
$routeProvider.when("/home", {
action: "home.view"
}).when("/devices", {
action: "split.devices"
}).when("/tracking", {
action: "split.tracking"
}).when("/alerts", {
action: "alerts.view"
});
$locationProvider.html5Mode(true);
}).controller('AppCtrl', function($scope, $route, $routeParams) {
// update the rendering of the page
render = function() {
// pull "action" value out of current route
var renderAction = $route.current.action;
// render path so we can start conditionally
// rendering parts of the page
var renderPath = renderAction.split(".");
var isHome = (renderPath[0] == "home");
var isDevices = (renderPath[0] == "devices");
var isTracking = (renderPath[0] == "tracking");
var isAlerts = (renderPath[0] == "alerts");
$scope.renderAction = renderAction;
$scope.renderPath = renderPath;
$scope.isHome = isHome;
$scope.isDevices = isDevices;
$scope.isTracking = isTracking;
$scope.isAlerts = isAlerts;
};
$scope.$on("$routeChangeSuccess", function($currentRoute, $previousRoute) {
render();
});
}).controller('HomeCtrl', function($scope) {
}).controller('DeviceCtrl', function($scope) {
}).controller('NavCtrl', ['$scope', '$location', function($scope, $location) {
// this toggles the 'active' class on/off in the navbar
$scope.navClass = function(page) {
var current = $location.path().substring(1);
return page === current ? 'active' : '';
};
}]);

Here I'm using SocketStream, AngularJS, Jade, and Twitter Bootstrap. I'm also using ss-angular here, but I'm not doing anything with it (yet) -- although I think it may help in the angular bootstrap process.

Technically, this example is really about composite views / routing with Angular - the other stuff is in there b/c that's what I'm using, but you could rip it out and use something completely different.

This example was based off this blog

SocketStream adheres to the single-page-app manifesto. There are ways to get around it, but it goes against the grain of what the framework wants to be. So, let's say you want to build in navigation, and you want to use Angular (why wouldn't you?). Navigation is a little tricky. You could use client-side partials/templates, and use ng-include directive to swap in a new ngView when your route changes (see $route).

AngularJS only allows one view per module, so the view is all or nothing. What if you want complex composite views. Let's say for example, you want a top level navbar, and then some views in the main pane are split - with the left side providing a submenu. Here's how that can be accomplished...

Here's what the navbar looks like with on the home link http://host/home

home

Here's the devices link http://host/devices, note that this is a split pane view. The left side is another submenu navigation list.

devices

Here's the tracking link http://host/tracking, not that this is also a split pane view. The left side shares the same submenu list as the devices link.

tracking

Finally, here's the alerts linke http://host/alerts, which is similar to the home link in that it takes up the whole content pane.

alerts

Note, that you can now add query params to the URL. For example, if you have a list of items in the sidebar, and you select one, that can be tacked onto the url as a query param, and you fire off a request to grab the data for that item. Exercise left for reader...

// This file automatically gets called first by SocketStream and must always exist
// Make 'ss' available to all modules and the browser console
window.ss = require('socketstream');
require('ssAngular');
require('/controllers');
ss.server.on('ready', function () {
// jQuery ready callback
$(function () {
console.log('jquery ready');
});
});
!!! 5
html(lang="en", ng-app="myApp", ng-controller="AppCtrl")
head
!= SocketStream
meta(charset="utf-8")
block title
title My Application Title
meta(name="viewport", content="width=device-width,initial-scale=1.0")
meta(name="description", content="todo")
meta(name="author", content="todo")
// if lt IE 9
script(src="http://html5shim.googlecode.com/svn/trunk/html5.js")
link(rel="shortcut icon", href="ico/favicon.ico")
link(rel="apple-touch-icon-precomposed", sizes="114x114", href="ico/apple-touch-icon-114-precomposed.png")
link(rel="apple-touch-icon-precomposed", sizes="72x72", href="ico/apple-touch-icon-72-precomposed.png")
link(rel="apple-touch-icon-precomposed", href="ico/apple-touch-icon-57-precomposed.png")
body
block content
block footer
footer
p © Me, Inc. 2012
@arxpoetica
Copy link

Cool.

@arxpoetica
Copy link

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