Skip to content

Instantly share code, notes, and snippets.

@fesor
Last active August 29, 2015 14:03
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 fesor/226fce4a4aee5fb30454 to your computer and use it in GitHub Desktop.
Save fesor/226fce4a4aee5fb30454 to your computer and use it in GitHub Desktop.
Configurable class directive for angular

Configurable Classname Directives

Alternative for ng-class + something like $rootScope.bodyClass with more pretty implementation.

Example:

<div app-configurable-class>
    <!-- directive:app-set-class my-container-classname -->
    <div class="nested-element" ui-view="nested">
        <!-- In template -->
        <!-- directive:app-sec-class neseted-container-classname -->
    </div>
</div>

It this case container will have classname ng-scope my-container-classname neseted-container-classname

angular.module('app')
.directive('appConfigurableClass', [
function () {
return {
restrict: 'A',
scope: true,
controller: function ($scope) {
$scope.classNames = [];
this.addClassNames = function (classNames) {
classNames = (classNames||'').trim().split(/\s+/);
$scope.classNames = $scope.classNames.concat(classNames).reduce(function (res, el) {
if (-1 === res.indexOf(el)) res.push(el);
return res;
}, []);
// apply changes
if (!$scope.$$phase)
$scope.$digest();
};
this.removeClassNames = function (classNames) {
classNames = (classNames||'').trim().split(/\s+/);
$scope.classNames = $scope.classNames.reduce(function (res, el) {
if (-1 === classNames.indexOf(el)) res.push(el);
return res;
}, []);
// apply changes
if (!$scope.$$phase)
$scope.$digest();
}
},
link: function (scope, el) {
scope.$watch('classNames', function (newClassNames, oldClassNames) {
(oldClassNames || []).forEach(function (className) {
el.removeClass(className);
});
(newClassNames || []).forEach(function (className) {
el.addClass(className);
});
});
}
}
}
])
.directive('appSetClass', function () {
return {
restrict: 'M',
require: '^appConfigurableClass',
link: function (scope, el, attributes, ctrl) {
ctrl.addClassNames(attributes.appSetClass);
// reset class names on scope destroy
scope.$on('$destroy', function () {
//reset class names
ctrl.removeClassNames(attributes.appSetClass);
});
}
}
});
describe('configurable class directives set', function () {
var el,
scope;
beforeEach(module('app'));
beforeEach(inject(function($rootScope) {
scope = $rootScope.$new();
}));
beforeEach(inject(function($compile) {
var tpl = '<div app-configurable-class><!-- directive:app-set-class foo bar --></div>';
el = $compile(tpl)(scope);
scope.$digest();
}));
describe('initialization', function () {
it('container should have given class', function () {
expect(el.hasClass('foo')).toEqual(true);
expect(el.hasClass('bar')).toEqual(true);
});
it('should reset class name on scope $destroy', function () {
expect(el.hasClass('foo')).toEqual(true);
expect(el.hasClass('bar')).toEqual(true);
scope.$destroy();
expect(el.hasClass('foo')).toEqual(false);
expect(el.hasClass('bar')).toEqual(false);
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment