angularng-class

ngClass - Dynamically add class name based on @input


I would like to dynamically add a class based on an input parameter but only if the input is an 'approved' string.

I have a component with an input and class array from which I want to check the input against:

@Input() modalSize?: string;
sizeClassList = ['xs', 'small', 'medium', 'large', 'xl'];

I have tried the following method within the component:

sizingMethod() {
  const isValid = this.sizeClassList.indexOf(this.modalSize) >= 0;
  if (isValid) {
    return 'modal__dialog--' + this.modalSize;
  }
}

Within the template:

<div class="modal__dialog" [ngClass]="sizingMethod()"> ... </div>

Essentially I would like to add an additional sizing class based on an input where the user only has to input the size.

If the user inputs [modalSize]="small", the class added will be 'modal__dialog--small' and if the user inputs [modalSize]="derp", no class will be added.

What is a good way to go about this?

*edit: Title edited to be more clear


Solution

  • Your approach is correct, although can be slightly improved:

    export type Size = 'xs' | 'small' | 'medium' | 'large' | 'xl';
    const sizeClassList: Array<Size> = ['xs', 'small', 'medium', 'large', 'xl'];
    
    export class YourComponent implements OnChanges {
      @Input() modalSize: Size;
      modalClassName: string;
    
      ngOnChanges(changes: SimpleChanges) {
        if (changes['modalSize']) {
          this.updateModalSize();
        }
      }
    
      private updateModalSize() {
        const isValid = sizeClassList.includes(this.modalSize);
        return 'modal__dialog--' + (isValid ? this.modalSize : 'medium');
      }
    }
    

    In template:

    <div class="modal__dialog" [ngClass]="modalClassName"> ... </div>
    

    When you do something like [ngClass]="sizingMethod()", especially without ChangeDetectionStrategy.OnPush, the method gets invoked every time Angular detect changes, so it can have poor performance.