Last active
August 29, 2015 14:02
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'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