angularcomponentsangular14angular2-hostbinding

What is best practice to assign multiple css classes to a component based on several conditions?


I am currently creating a components library. I am facing the problem how to apply multiple classes to it's host element based on several conditions.

Assuming I have the following component:

@Component({
    selector: 'abc-button',
    templateUrl: './abc-button.component.html',
    styleUrls: ['./abc-button.component.sass'],
})
export class AbcButtonComponent {

    @Input() title?: string
    @Input() type: 'primary' | 'secondary' | 'tertiary' = 'primary'
    @Input() state: 'stateA' | 'stateB' | 'stateC' = 'stateA'
    @Input() dropdown? : boolean = false
    @Input() size?: 'small' | 'medium' | 'large' = 'medium'
    @Input() disabled?: boolean = false

 ...
}

What would be best practice to assign a lot of classes to the host element based on it's input variables.

What I am currently doing is something like this:

@HostBinding('class.abc-button__type--primary')
get typeIsPrimary() { return this.type == 'primary' }

@HostBinding('class.abc-button__type--secondary')
get typeIsSecondary() { return this.type == 'secondary' }

...

@HostBinding('class.abc-button__state--stateA')
get typeIsStateA() { return this.state == 'stateA' }

@HostBinding('class.abc-button__state--stateB')
get typeIsStateB() { return this.state == 'stateB' }

...

For booleans this would be a good way:

@HostBinding("class.disabled") @Input() disabled: boolean;

But how about the others?

I have the feeling, that this is not best practice. On every user interaction every getter is called multiple times. Is there a better way to bind classes to the host element which can also be updated during runtime?


Solution

  • You can assign classes dynamically like that:

    @HostBinding('class')
    get hostClasses(): string[] {
      return [
        this.type === 'primary' ? 'primary' : ' secondary',
        this.disabled === true ? 'disabled' : '',
        'other-class'
      ]
    }
    

    you can have Type defined as Enum:

    enum Type {
     Primary = 'primary',
     Secondary = 'secondary',
    }
    

    then it's even easier:

    @HostBinding('class')
    get hostClasses(): string[] {
      return [
        this.type,
        this.disabled === true ? 'disabled' : '',
        'other-class'
      ]
    }
    

    And use OnPush to achieve better performance