How to manipulate styles of directive in AngularJS?


I'm writing a component using AngularJS and AngularJS directives.

I'm doing something like this:

var MyApp = angular.module('MyApp', []);

MyApp.directive('myTag', function() {
    return { /* Some logic here*/ }
});

I want to be able to change style of my component (using CSS), something like this:

<my-tag class="MyClass"></my-tag>

Besides this I want to be able to manipulate all elements style inside my component (HTML markup inside of my-tag).

Do you have any advice or useful examples how to manipulate the style properties of custom tags using AngularJS?

This should do the trick.

var MyApp = angular.module('MyApp', []);

MyApp.directive('myTag', function() {
    return { 
      link: function(scope, element, attributes){
        element.addClass('MyClass');
      }
    }
});

This is how AngularJS adds core CSS styles:

angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}</style>');

You can find this code in angular.js v1.2.0-rc.2.

EDIT

In a custom directive, I use this solution to bundle CSS stylesheets in the directive:

  var outputColorCSS = {
    selector: 'span.ouput-color',
    rules: [
        'display: inline-block',
        'height: 1em',
        'width: 5em',
        'background: transparent',
        'border: 3px solid black',
        'text-align: center',
        'font-weight: bold',
        'font-size: 0.8em'
    ]
  };
  var outputColorStyleSheet = outputColorCSS.selector + outputColorCSS.rules.join(';');
  angular.element(document).find('head').prepend('<style type="text/css">' + outputColorStyleSheet + '</style>');

Then you can use class="ouput-color" in your directive templates.

I found it very clean and useful.


I'm a little late to the party, but why aren't you all using the built in .css() method?

just use:

link: function(scope, elem, attr, ctrl)
{
    elem.css({'display': 'block', 'height': '100%', 'width': '100%'});

}

or whatever css you desire.


You can put custom styles in a directive's declaration with a parameter, just like you exemplified.

In order to declare a style like that, you have to define a variable to hold the custom styles:

scope: {
    myClass: '@myClass'
  },

And then set that parameter in the directive's template, like this:

<my-tag my-class="CustomClass"></my-tag>

Finally, in the template of the directive itself, reference that class:

<h1 class="{{myClass}}">{{myContent}}</h1>

I made a plunker that shows how you can customize styles in a directive, check it out here .


Plunker

To manipulate the css style through an attribute directive, you could do something like this:

var app = angular.module('colorSwap', []);

app.directive('styleChanger', function() {
  return {
    'scope': false,
    'link': function(scope, element, attrs) {
      var someFunc = function(data)
      {
        /* does some logic */
        return 'background-color:' + data;
      }
      var newStyle = attrs.styleChanger;
      scope.$watch(newStyle, function (style) {
        if (!style) {
          return ;
        }
        attrs.$set('style', someFunc(style));
      });
    }
  };
});

Some html:

<div ng-app="colorSwap">
  <input type="txt" ng-init="colorName= 'yellow'" ng-model="colorName" />
  <div style-changer="colorName">this is the div content</div>
</div>

To make an element directive, change it's own style, something like this:

app.directive('elementWithStyle', function() {
  return {
    'restrict' : 'E',
    'scope': {},
    'controller': function($scope) {
      $scope.someStyle = 'Cyan';
      $scope.someFunc = function() { $scope.someStyle = 'purple' };
    },
    'template': '<div style="background: {{someStyle}}" ng-click="someFunc()"> click me to change colors </div>'
  }
});

And the html:

<div ng-app="colorSwap">
  <element-with-style>123</element-with-style>
</div>

I hope this helps. The rest of the answers cover class manipulation more or less.


For css manipulation inside of the childs of your directive try this:

var MyApp = angular.module('MyApp', []);

MyApp.directive('myTag', function() {
    return { 
      link: function(scope, element, attr){

       // For your tag
       element.addClass('MyClass');

       // For elements inside your directive tag
       var tag_childs = element[0].childNodes;
       for(var i = 0; i < element[0].childElementCount; i++){

          tag_childs[i].style.height = '70px';

        }

      }
    }
});

Here is an example, please note that this is probably not the best use of AngularJS, being declarative, you would likely want to just put the classes on the markup. However, just so you understand what's going on, let me demonstrate a simple directive to do what you first asked.

var MyApp = angular.module('MyApp', []);

MyApp.directive('myTag', function($compile) {
    return {
        restrict: 'E', // this means it will be an element
        link: function(scope, element, attrs, ctrl) {
            // First, I included the $compile service because it will be needed
            // to compile any markup you want to return to the element.

            // 1. Add the class, as you wanted
            element.addClass('MyClass');

            // 2. Add markup
            var html = '<div>Hello World</div>';
            //Compile it and add it back
            $compile(html)(scope);
            element.html(html);
        }
    };
});

Finally, on your markup, you just put this in:

<my-tag />

app.directive('bookslist', function() {

    return {
    	scope: true,
        templateUrl: 'templates/bookslist.html',
        restrict: "E",
        controller: function($scope){

        },
        link: function(scope, element, attributes){
        element.addClass('customClass');
      }

    }

});
.customClass table{
	background: tan;

}
.customClass td{
	border: 1px solid #ddd;

}
<!DOCTYPE html>
<html>

<head>
    <link href="app.css" rel="stylesheet">
    <script type="text/javascript" src="angular.min.js"></script>
    <script type="text/javascript" src="app.js"></script>
    <title>Task</title>
</head>

<body ng-app="app">
    <div ng-controller="myCtrl">
      
         <bookslist></bookslist>


    </div>
</body>

</html>


Angular

app.directive("time",function(){
            var directive={};
            directive.restrict="A";
            directive.link=function(scope,element,attr,ctrl){                   
                element.css({
                    backgroundColor:'#ead333'
                });
            }
            var time=new Date().toTimeString();
            directive.template=time;
            return directive;
        });

HTML

The times is <span time></span>

I didn't found the perfect solution just yet, but I'm following John Papa's styling of controllers even with directives:

  • the directive is a folder (directiveName.directive)
  • 3 files inside: directiveName.directive.js, directiveName.template.html, directiveName.styles.css
  • use templateUrl when declaring the directive. The template has the link to the css file, as usual

I found it to be very clean and follows a pattern. The bad side of it is that you create several <link> tags near the directives in the rendered HTML (not seem to be a issue still, though). Check out this comment too.

That being said, take a look at Angular 1.5 component's. It's relatively new and has a much better approach. Now I use directives only for DOM manipulation (not reusability as components).