Skip to content

Instantly share code, notes, and snippets.

@CitizenOfRome
Last active August 29, 2015 14:02
Show Gist options
  • Save CitizenOfRome/7b6ed575b9d5e90b7e1f to your computer and use it in GitHub Desktop.
Save CitizenOfRome/7b6ed575b9d5e90b7e1f to your computer and use it in GitHub Desktop.
AngularJS with-locals directive, used to rename local scope variables to create reusable modules with ng-include
'use strict';
// http://stackoverflow.com/a/17876761/937891
// <div dg-with-locals dg-with-locals-cars="allCars | onlyNew">{{locals.cars}}</div>
angular.module('adminApp')
.directive('dgWithLocals', ['$parse', '$rootScope',
function ($parse, $rootScope) {
return {
scope: true,
compile: function (element, attributes) {
// for each attribute that matches locals-* (camelcased to locals[A-Z0-9]),
// capture the "key" intended for the local variable so that we can later
// map it into $scope.locals (in the linking function below)
var mapLocalsToParentExp = {};
for (var attr in attributes) {
if (attributes.hasOwnProperty(attr) && /^dgWithLocals[A-Z0-9]/.test(attr)) {
var localKey = attr.slice(12);
console.log(attr);
localKey = localKey[0].toLowerCase() + localKey.slice(1);
mapLocalsToParentExp[localKey] = attributes[attr];
}
}
var updateParentValueFunction = function ($scope, localKey) {
// Find the $parent scope that initialized this directive.
// Important in cases where controllers have caused this $scope to be deeply nested inside the original parent
var $parent = $scope.$parent;
try {
while (!$parent.hasOwnProperty(mapLocalsToParentExp[localKey])) {
$parent = $parent.$parent;
}
console.debug('Accepted parent', localKey);
} catch(err) {
console.warn('Parent scope not found', err.message, localKey);
$parent = $rootScope;
}
return function (newValue) {
try {
$parse(mapLocalsToParentExp[localKey]).assign($parent, newValue);
} catch(err) {
console.warn(err.message, localKey, mapLocalsToParentExp[localKey]);
}
};
};
return {
pre: function ($scope) {
// setup `$scope.locals` hash so that we can map expressions
// from the parent scope into it.
$scope.locals = {};
var applyLocalKey = function (localKey) {
return function (newValue) {
$scope.locals[localKey] = newValue;
};
};
for (var localKey in mapLocalsToParentExp) {
// For each local key, $watch the provided expression and update
// the $scope.locals hash (i.e. attribute `locals-cars` has key
// `cars` and the $watch()ed value maps to `$scope.locals.cars`)
$scope.$watch(
mapLocalsToParentExp[localKey],
applyLocalKey(localKey),
true
);
// Also watch the local value and propagate any changes
// back up to the parent scope.
var parsedGetter = $parse(mapLocalsToParentExp[localKey]);
if (parsedGetter.assign) {
$scope.$watch('locals.' + localKey, updateParentValueFunction($scope, localKey));
}
}
}
};
}
};
}]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment