Skip to content

Instantly share code, notes, and snippets.

@uglow
Last active August 29, 2015 14:02
Show Gist options
  • Save uglow/34450d0e31c2b6c56759 to your computer and use it in GitHub Desktop.
Save uglow/34450d0e31c2b6c56759 to your computer and use it in GitHub Desktop.
AngularJS Melbourne - Companion Demo Files
//---------- sitemap.jsonp ----------//
mwApp.SITEMAP=[
{
"title": "Section Title",
"children": [
{
"title": "Page title",
"children": [
{
"id": "a65079e4-6327-4393-9bec-c537066a2aa0",
"title": "Domestic product",
"route": "/view/domestic-parcels.json",
"faq": "DomPar100"
},
{
"id": "147a8cb3-4b57-4fea-8ef7-02176a4aa6ee",
"title": "Internationl Product",
"route": "/view/parcel-post.json",
"faq": "ParPos100"
},
//...
//---------- index.html ----------//
<!DOCTYPE html>
<html lang="en" id="ng:app" ng-app="mwApp" ng-controller="MainController">
<head>
<!-- ... -->
<script>
// Load the sitemap.jsonp BEFORE loading the AngularJS files
document.write('<script src="/m-static/sitemap.jsonp"><' + '/script>');
</script>
</head>
<body ...>
<!-- ... -->
<script>
// Load AngularJS at the end of the BODY tag
document.write('<script src="jslib/angular.js"><' + '/script>');
document.write('<script src="jslib/angular-route.js"><' + '/script>');
document.write('<script src="jslib/angular-animate.js"><' + '/script>');
document.write('<script src="jslib/angular-sanitize.js"><' + '/script>');
document.write('<script src="jslib/global.js"><' + '/script>');
document.write('<script src="js/core.js"><' + '/script>');
//... Other modules ...
</script>
</body>
</html>
// Routing... so when do we see $routeProvider.when() ???
//---------- moduleA/routes.jsonp ----------//
moduleRoutes = [
{
"title": "Tools",
"type": "section",
"menuPriority": 100,
"children": [
{
"id": "ModuleA",
"title": "Calculator",
"route": "/view/calc",
"template": "partials/ModuleA/pac.html",
"faq": ["CalPos100", "Calculator"],
"icon": "a001-calculate",
"menuPriority": 102,
"promoted": false
},
{
"id": "ModuleA_Location",
"title": "Calculator",
"route": "/view/calc/domestic-location",
"template": "partials/moduleA/calc-domestic-location.html",
"faq": ["CalPos100", "Calculator"],
"parentRoute": "/view/pac",
"hidden": true
},
//...
//---------- sitemap.jsonp ----------//
// Compare to above routes, this needs to massaged into shape. (menuPriority missing,
// template property is useless)
// Our CMS module does this itself by walking the tree and changing the nodes as required
mwApp.SITEMAP=[
{
"title": "Section Title",
"children": [
{
"title": "Page title",
"children": [
{
"id": "a65079e4-6327-4393-9bec-c537066a2aa0",
"title": "Domestic product",
"route": "/view/domestic-parcels.json",
"faq": "DomPar100"
},
{
"id": "147a8cb3-4b57-4fea-8ef7-02176a4aa6ee",
"title": "Internationl Product",
"route": "/view/parcel-post.json",
"faq": "ParPos100"
},
//...
//---------- _moduleA.js ----------//
var mod = angular.module('moduleA', [...]);
function getRoutes() {
var routes = [];
// Way of separating the code from the data at design-time, but including
// the data during compile-time...
////@@include('../includes/moduleA/routes.jsonp')
return routes;
}
configureModuleRoutes(mod, getRoutes());
function configureModuleRoutes (mod, sitemap) {
'use strict';
// Create the routes in the $routeProvider
mod.config(['$routeProvider', 'RouteServiceProvider', ...
function ($routeProvider, RouteServiceProvider, ...) {
// Add the routes to the RouteService
RouteServiceProvider.registerSitemapRoutes($routeProvider, ..., sitemap);
}]);
}
//---------- RouteService.js ----------//
//...
this.registerSitemapRoutes = function ($routeProvider, ..., sitemap) {
// Add the tree-data to the sitemap
addToSiteMap(sitemap);
// We need to extract the routing information into a routing-object
// (containing just the routes, no UI nodes (like "Tools"), no hierarchy)
var routeObject = getRouteObjectFromSitemapTree(sitemap);
createRouteConfig($routeProvider, routeObject, routes);
return routes;
};
function createRouteConfig($routeProvider, routeObject, routes) {
// Setup our routes based on the data in the ROUTES collection
for (var routeKey in routeObject) {
var routeItem = routeObject[routeKey],
routeTemplate = routeItem.template;
/**/ $routeProvider.when(routeItem.route, { templateUrl: routeTemplate });
//...
// Append the route to the parentRouteConfig
routes[routeKey] = routeObject[routeKey];
}
}
//...
// Finally, at RUNTIME, the RouteService has the following methods:
// getRoutes() : Object-map
// getSitemap(): Array (tree) // Used by the navigation menu
// getRoutes() returns an object...
TNC: Object
id: "TNC"
title: "Terms & Conditions",
menuPriority: 953
promoted: false
route: "http://mysite.com.au/terms-conditions.html"
routeParams: Array[0]
template: false,
hidden: false,
__proto__: Object
TRACKING: Object
YOUTH_REG_FORM: Object
YOUTH_REG_FORM_THANKYOU: Object
a2ec7b37-3c29-4c18-bdee-87e78183cc1d: Object
a0430f92-4979-4ab0-9dfd-9a23b69422cf: Object
a1876c79-c833-46da-9ebb-82fc7e8cf9f0: Object
//---------- Gruntfile.js ----------//
//...
concat: {
/* This builds the moduleName.js file in the output/js folder */
moduleJS: {
files: [
{
expand: true,
cwd: '<%= paths.src.jsDir %>',
src: ['<%= paths.src.jsFilesToIncludeFirst %>', '<%= paths.src.jsFiles %>', '!<%= paths.test.jsFiles %>'],
dest: '<%= paths.dest.jsDir %>',
rename: function(dest, src) {
// use the source directory to create the file
// example with your directory structure
// dest = 'dev/js/'
// src = 'module1/js/main.js'
return dest + src.substring(0, src.indexOf('/')) + '.js';
}
}
]
}
}
//...
//----------- paths.js ----------//
paths: {
src: {
//...
jsDir: 'src/modules/',
jsFiles: '**/*.js',
jsFilesToIncludeFirst: '**/_*.js' //<------ THIS is required so that your conc
///...
}
}
//----------- _module1.js ----------//
(function (angular) {
'use strict';
// Module DEFINITION
var mod = angular.module('module1', ['core']);
})(window.angular);
//----------- _module1Controller.js ----------//
(function (angular) {
'use strict';
// Module REFERENCE
var mod = angular.module('module1');
mod.controller(...);
//...
})(window.angular);
//---------- Example of form policies ----------//
// DISPLAY_FILTERS - these represent an expression which which will be tested to determine whether to show an error
angular.module('ui.formPolicy.displayError.onSubmit', [])
.constant('formPolicyErrorExistsWhen', (function () {
return function (formName, fieldName) {
return formName + '._formSubmitAttempted && ' + fieldName + '.$invalid';
};
})());
angular.module('ui.formPolicy.displayError.onSubmitOrDirty', [])
.constant('formPolicyErrorExistsWhen', (function () {
return function (formName, fieldName) {
return '(' + formName + '._formSubmitAttempted || ' + fieldName + '.$dirty) && ' + fieldName + '.$invalid';
};
})());
// App module definition which includes the desired form policies
angular.module('mwApp', ['ngSanitize', 'ngRoute', 'ngAnimate', 'core',
// Form policy modules. Need to load modules for each behaviour
'ui.formPolicy.checkForErrors.onBlurUntilSubmitThenOnChange',
'ui.formPolicy.displayError.onSubmitOrDirty',
'ui.formPolicy.focusBehaviour.onSubmitFocusFirstField',
//...
]);
//---------- some-partial.html (DESIGN TIME)----------//
// Can add your own directives to the input using ff-my-directive="..."!
<form-input id="businessAdviceForm-email" name="email" required="true" label="Email address"
ff-class="span12" ff-type="email" ff-ng-model="business.email"
ff-maxlength="55" ff-minlength="33"
field-errors="{required: 'Please enter a valid email address', email: 'Please enter a valid email address'}"
></form-input>
//---------- some-partial.html (RUN TIME)----------//
// Example: https://m.auspost.com.au/view/solutions/businessadvice
<div>
<label for="businessAdviceForm-email">Email address
<span class="required ng-isolate-scope" aria-hidden="true" ng-class="{'ng-hide': hide}" hide="!(true)"></span></label>
<div class="controls-row">
<input id="businessAdviceForm-email" name="email"
class="span12 ng-pristine ng-invalid ng-invalid-required ng-valid-email" type="email"
ng-model="business.email" maxlength="55" ng-required="true" aria-required="true"
field-error-controller="" aria-invalid="false" required="required">
<span ng-transclude=""></span>
</div>
<div class="container-error" id="businessAdviceForm-email-errors">
<span class="sr-only" aria-hidden="true" id="businessAdviceForm-email-errors-aria"></span>
</div>
</div>
//-----------------------------------
// Core function used by the <form-input> directive that copies directive-aliases onto the actual input element:
decorateInputField: function (inputElem, hostElement, attr, id, name, required) {
inputElem.attr('id', id).attr('name', name);
// Apply all of the ff-* attributes to the input element. Use the original attribute names
// attr.$attr contains the snake-case names e.g. 'form-field' vs camel case 'formField'
for (var a in attr.$attr) {
if (a.indexOf('ff') === 0) { // Don't search for 'ff-' as the '-' has been replaced with camel case now
var origAttrName = attr.$attr[a].substr(3);
inputElem.attr(origAttrName, attr[a]);
// Remove all attributes off the host element
hostElement.removeAttr(attr.$attr[a]);
}
}
// Make aria-required's value an interpolation-directive...
inputElem.attr('ng-required', required);
inputElem.attr('aria-required', '{{!!(' + required + ')}}'); // evaluates to true / false
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment