2

I want to use HostBinding decorator in order to add a class, which cannot be hardcoded like @HostBinding('class.myClass').

I know there is a possibility to bind it to the whole class attribute like @HostBinding('class'), but that will obviously reset all classes added directly to my host element in the place where it is used.

So is it possible to use HostBinding, but only to add one class and preserve all previously added classes in html?

Currently I ended up with uglier solution:

@Component({
    ...
})
class MyComponent implements OnInit {
    constructor(private hostElement: ElementRef,
                private renderer: Renderer2) { }

    ngOnInit() {
        const randomClass = `dynamic-${Math.floor(Math.random() * 10) + 1}`;
        this.renderer.addClass(this.hostElement.nativeElement, dynamicClass);
    }
}
isherwood
  • 58,414
  • 16
  • 114
  • 157
Clem
  • 11,334
  • 8
  • 34
  • 48
  • 1
    this @HostBinding('class.my-class') myclass = true; add my-class to :host element – Whisher Oct 16 '17 at 16:02
  • Yes, but as I said, I don't know in advance the class name I wan't to add. That's why I use Math.random in the example. Therefore I cannot use hardcoded `class.my-class` – Clem Oct 16 '17 at 17:33
  • 1
    I can see the point even if I don't understand how to style the element without knowing the class - btw I think your way is the way to go – Whisher Oct 16 '17 at 17:53
  • 1
    Hehe, yes absolutely valid point. :D In real world scenario this class actually isn't totally dynamic. Someone is writing a styles for it, we just don't know it in that given time in code. Thanks @Whisher – Clem Oct 16 '17 at 17:58
  • 1
    https://alligator.io/angular/using-renderer2/ you can also use a directive you could add the class dynamically using @Input – Whisher Oct 16 '17 at 18:47
  • Well that's a valid option as well. I will see which one will make more sense with time. Thanks! – Clem Oct 16 '17 at 19:31

1 Answers1

4

Overriding the native class="" attribute with an @Input() class: string; looks promising. I haven't tested this very thoroughly, but it seems to work so far.

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

@Component({
    selector: 'gist-keeps-class',
    template: 'this component keeps class="class" attributes'
})
export class KeepsClass {

    @Input() booleanInput: boolean = false;
    @Input() stringInput: 'some-thing' | 'another-thing' | 'a-third-thing' = 'another-thing';

    @Input() class: string = ''; // override the standard class attr with a new one.
    @HostBinding('class')
    get hostClasses(): string {
        return [
            this.class, // include our new one 
            this.booleanInput ? 'has-boolean' : '',
            this.stringInput
        ].join(' ');
    }

}

template with this:

<gist-keeps-class 
  class="some classes" 
  [booleanInput]="true" 
  [stringInput]="some-thing"
></gist-keeps-class>

will output this:

  <gist-keeps-class class="some classes has-boolean some-thing" >
    this component keeps class="class" attributes
  </gist-keeps-class>

gist

arniebradfo
  • 1,141
  • 11
  • 18