Reputation: 2560
After a project with Web Components, i'm going back to AngularJS. I'm frustrated by the fact I can't find a proper way for a directive to keep its CSS internal (or encapsulated).
With web component I hadn't this problem since there is already a style tag that can be embedded in the template.
That's not the case with AngularJS directives.
Until here what I saw is :
1) define an CSS rule in an external file : my-directive {color:red;}, but this is not encapsulation.
2) define an internal rule with element.css({}); inside link function, but in this case the style is applied inline and thus is too heavy and cannot be easily override by external css.
Are there other ways ?
Thanks
Upvotes: 5
Views: 9740
Reputation: 1259
There is a one angular service already created on GitHub, you can load your css files dinamically, maybe it can be helpful
https://github.com/Yappli/angular-css-injector
Or you can give a chance to GruntJS and you can have a very nice project structure, every module/folder can have own css file, and Grunt will bundle all that files into one (or many, it depends how you configure). It's easy to manage and change, but also you have only one file loaded on your page. Maybe these links can be helpful to find Grunt module that can help you.
https://www.npmjs.org/package/grunt-contrib-cssmin
Upvotes: 1
Reputation: 4217
One Method you can try is declaring and assigning the styles in JavaScript.
Declare a Style object.
styles = {
background: 'green',
color: 'black'
};
Assign the object to a template using ng-style
<div ng-style="$ctrl.styles">
My Component with local CSS
</div>
Here are some the following advantages using this method
Full Example
//Component
class myComponent {
constructor( myCSSService ) {
this.styles = {
background: 'black',
color: 'white'
};
this.myCSSService = myCSSService;
}
}
myComponent.$inject = [ 'myCSSService' ];
angular.module( 'myModule', [] )
.component( 'myComponent', {
controller: myComponent,
bindings: {},
template: `
<div ng-style="$ctrl.styles">
My Component with local CSS
</div>
<div ng-style="$ctrl.myCSSService.styles">
My Component with Injected CSS
</div>
`,
} );
//Style Service
class myCSSService{
constructor( ) {
this.styles = {
background: 'green',
color: 'black'
};
}
}
angular.module( 'myCSSModule', [] )
.service( 'myCSSService', myCSSService );
Upvotes: 1
Reputation: 1266
You can allow users to pass in class and/or style elements on the directive itself and you can have fine-grained control over how that class/style is applied to your template. The first step is to declare your directive with replace : true
, which will then carry any class/style information to your underlying template. For instance:
app.directive("myDirective",function(){
return {
restrict:'AE',
replace : true,
template: '<div>This is my directive</div>'
};
});
When you use this in HTML like this:
<my-directive class="red"></my-directive>
The resulting HTML will be:
<div class="red">This is my directive</div>
As you can see, the replace directive removes the directive tag, but preserves the attributes of the directive and applies them to the template. Therefore, in your directive, you don't technically have to do anything and your users can pass in style information to be automatically applied as necessary.
However, let's assume that your directive layout is more complicated:
app.directive("myDirective",function(){
return {
restrict:'AE',
replace : true,
template: '<div><div>My Title</div>My content</div>'
};
});
Then you can explicitly indicate additional class/style references that your directive can optionally use and where the class would be applied. For example:
<my-directive class="red" class-title="blue"></my-directive>
And then, in your directive's compile or link function, you can set the class for internal template items if these are indicated:
app.directive("myDirective",function(){
return {
restrict:'AE',
replace : true,
template: '<div><div>Title</div>Content</div>',
compile : function(elem,attr){
if (attr.classTitle){
var titleElem = angular.element(elem.children()[0]);
titleElem.attr("class",attr.classTitle)
}
}
};
});
Which would result in the following:
<div class="red" class-header="blue">
<div class="blue">My Title</div>
My Content
</div>
There's even more good things you can do with transclusion so that people can use their own content and styling for elements.
Upvotes: 0