63

I am currently learning Angular 2. I understood how to use the Angular Renderer to set an ElementStyle, but now I would like to use the Renderer method:

setElementClass(renderElement: any, className: string, isAdd: boolean) : void

My question is how can I import a CSS class to my attribute directive? Do I have to convert my CSS class to JSON?

1
  • What do you mean by importing a css class? className is string so why you have to load or convert or import css class? Commented Sep 22, 2016 at 12:52

4 Answers 4

129

Original OP was asking how to use Renderer. I've included the @HostBinding for completeness.

Using @HostBinding

To add a class to an element you can use @HostBinding

import { Directive, HostBinding} from '@angular/core';

@Directive({
  selector: '[myDirective]',
})
export class MyDirective {

  @HostBinding('class')
  elementClass = 'custom-theme';

  constructor() {
  }
}

Using @HostBinding with multiple classes

To make multiple classes more comfortable to use, you can use the ES6 getter and join the classes together before returning them:

import { Directive, HostBinding} from '@angular/core';

@Directive({
  selector: '[myDirective]',
})
export class MyDirective {
  protected _elementClass: string[] = [];

  @Input('class')
  @HostBinding('class')
  get elementClass(): string {
      return this._elementClass.join(' ');
  }
  set(val: string) {
      this._elementClass = val.split(' ');
  }

  constructor() {
      this._elementClass.push('custom-theme');
      this._elementClass.push('another-class');
  }
}

Using Renderer

The more low level API is Renderer2. Renderer2 is useful when you have a dynamic set of classes you would like to apply to an element.

Example:

import { Directive, ElementRef, Renderer2 } from '@angular/core';

@Directive({
  selector: '[myDirective]',
})
export class MyDirective {

  constructor(private renderer: Renderer2, hostElement: ElementRef) {
    renderer.addClass(hostElement.nativeElement, 'custom-theme');
  }
}
Sign up to request clarification or add additional context in comments.

6 Comments

I'm using for loop of classes array, is that practical?
For multiple classes you should perform a loop. If you take a look at the source you'll see Angular calls the classList.add method. While this native method supports multiple arguments, the Angular implementation only allows passing one class name at a time.
pushing classes from the constructor doesn't seem to work. But it works from ngAfterViewInit
The setter never seems to get called, causing any initial classes of the host to be lost :-(
You don't need to DI the renderer or manipulate the existing classes instead use @HostBinding('class.your-class') - stackoverflow.com/a/58071653/1148107
|
13

Why would you want to use the Renderer or Renderer2 class? The preferred way to do this in a directive is to use the @HostBinding decorator.

Example:

import { HostBinding } from '@angular/core';

@Directive({
    selector: '[myDirective]'
})
export class MyDirective {

    @HostBinding('class')
    className = 'my-directive-css-class';
}

4 Comments

This is useful if you want to add a class based on some other property, i.e. dynamically:
I think this is only useful to completely replace the classes that may already be defined in the HTML. How would I add a class with this method? Renderer seems more flexible.
This syntax is better : @HostBinding('class.isPlaying') class_isPlaying = true; (see this stackoverflow.com/a/35183074/16940). It will toggle classes as opposed to just wiping out the whole attribute.
@Simon_Weaver That syntax probably was better, and still is a good choice if you need to toggle one class based on a property. It seems however that in recent versions of Angular (e.g. 10) the @HostBinding('class') does not wipe out the whole attribute. It behaves just like the [class] binding in the template, in that you can give it classes as a space delimited string, an array of strings, or even conditional classes as an object (note however, that it does not detect changes within an array or object). ref: angular.io/guide/…
10

Just another way to do it but easier and more understandable to me.

You let me know what you think

import { Directive, Input} from '@angular/core';

@Directive({
  selector: '[whatever]',
  host: {
    // These are like ngClass class condition values
    '[class.custom-class1]': 'true', // Default class for example
    '[class.custom-class2]': 'foo === "expectedValue"', // Predicate1
    '[class.custom-class3]': 'foo !== "expectedValue"', // Predicate2
  },
})
export class WhateverDirective {
  @Input() foo: string;
}

1 Comment

eslint thinks otherwise as of 12/2022
6

Example of how to use Renderer and ElementRef to add css class to element.

@Directive({
   selector: '[whatever]'
})
class WhateverDirective {
   constructor(renderer: Renderer, el: ElementRef) {
       renderer.setElementClass(el.nativeElement, 'whatever-css-class', true);
   }
}

The whatever-css-class is defined in a css file, which is referenced in html

4 Comments

Yes absolutely, so far I understood the setElementClass function, but where lays the whatever-css-class, an attribute directive doesn't have an css file or is there a possibility to add one ?
Right, so what you can do is define class in css file which you are referencing in html, so that way it will be applied to the element.
Renderer class is now deprecated. Use Renderer2 instead.
You don't need to DI the renderer instead use @HostBinding('class.your-class') - stackoverflow.com/a/58071653/1148107

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.