htmlangularangular-materialangular-directive

String interpolation via directive


Most commonly you would set the mat-option text in a way like this.

<mat-option [value]="type.key">{{ type.value }}</mat-option>

The thing is I have a directive that processes the string, before setting it on the element's inner text. Which overrides the HTML of the mat option.

<mat-option [value]="type.key" [appTransform]="type.value"></mat-option>

So is there a way to set the interpolated value via the directive?


Solution

  • You can use Renderer2 and ElementRef to transform the text and insert it using appendChild method.

    @Directive({
      selector: '[appTransform]',
      standalone: true,
    })
    export class AppTransformDirective {
      str: InputSignal<string> = input.required<string>({
        alias: 'appTransform',
      });
      renderer = inject(Renderer2);
      element = inject(ElementRef);
      ngOnInit() {
        const transformed = `${this.str()} car`;
        const text = this.renderer.createText(transformed);
        const elementToInsertIn = this.element.nativeElement.querySelector(
          '.mdc-list-item__primary-text'
        );
        this.renderer.appendChild(elementToInsertIn, text);
      }
    }
    

    Full Code:

    import {
      Component,
      Directive,
      input,
      InputSignal,
      ElementRef,
      Renderer2,
      inject,
    } from '@angular/core';
    import { FormsModule } from '@angular/forms';
    import { MatInputModule } from '@angular/material/input';
    import { MatSelectModule } from '@angular/material/select';
    import { MatFormFieldModule } from '@angular/material/form-field';
    
    interface Food {
      value: string;
      viewValue: string;
    }
    
    @Directive({
      selector: '[appTransform]',
      standalone: true,
    })
    export class AppTransformDirective {
      str: InputSignal<string> = input.required<string>({
        alias: 'appTransform',
      });
      renderer = inject(Renderer2);
      element = inject(ElementRef);
      ngOnInit() {
        const transformed = `${this.str()} car`;
        const text = this.renderer.createText(transformed);
        const elementToInsertIn = this.element.nativeElement.querySelector(
          '.mdc-list-item__primary-text'
        );
        this.renderer.appendChild(elementToInsertIn, text);
      }
    }
    
    /**
     * @title Basic select
     */
    @Component({
      selector: 'select-overview-example',
      templateUrl: 'select-overview-example.html',
      imports: [
        MatFormFieldModule,
        MatSelectModule,
        MatInputModule,
        FormsModule,
        AppTransformDirective,
      ],
    })
    export class SelectOverviewExample {
      cars: string[] = ['volvo', 'saab', 'mercedes', 'audi'];
    }
    

    Stackblitz Demo