Create custom mat-* components that will appear beneath inputs?

Viewed 20

Is there a way to registered components so that they will appear within a mat-form-field within the same element (~div.mat-form-field-subscript-wrapper) as a mat-error or mat-hint?

For example:

<!-- Desired, but places the component above the input, not below it -->
<form [formGroup]="componentForm">
  <mat-form-field>
    <input type="text" formControlName="name">
    <mat-error-required [abstractControl]="componentForm.controls.name"></mat-error-required>
  </mat-form-field>
</form>
<!-- Functional -->
<form [formGroup]="componentForm">
  <mat-form-field>
    <input type="text" formControlName="name">
    <mat-error>
      <mat-error-required [abstractControl]="componentForm.controls.name"></mat-error-required>
    </mat-error>
  </mat-form-field>
</form>

mat-error-required.component.html

<mat-error
  *ngIf="
    (formControl && formControl?.errors?.required) ||
    (abstractControl && abstractControl?.errors?.required)
  "
>This field is required.</mat-error>

mat-error-required.component.ts

import { Component, Input, OnInit } from '@angular/core';
import { AbstractControl, FormControl } from '@angular/forms';

@Component({
  selector: 'mat-error-required',
  templateUrl: './mat-error-required.component.html',
  styleUrls: ['./mat-error-required.component.scss']
})
export class MatErrorRequiredComponent implements OnInit {
  
  @Input() formControl?: FormControl;
  @Input() abstractControl?: AbstractControl;

  constructor() { }

  ngOnInit(): void {
  }

}
1 Answers

I imagine that you can change the "parent" of the element.

First you need get the "form-field" tag and change the parent to the div with class mat-form-field-subscript-wrapper

Some like

@Component({
  selector: 'custom-error',
  template:`<span *ngIf="visible" class="custom">I'm a custom</span>`,
  styles:[`
  span {
    color:red;
  }
  `]
})
export class CustomError implements OnInit{
  private parent:HTMLElement|null=null;
  constructor(private el:ElementRef,@Optional() @Host() formfield:MatFormField){
    this.parent=formfield?formfield.getConnectedOverlayOrigin().nativeElement:null
  }
  @Input()visible=false;
  ngOnInit(){
    if (this.parent)
    {
        (this.parent.getElementsByClassName('mat-form-field-subscript-wrapper')[0] 
               || {} as any).appendChild(this.el.nativeElement)
    }
  }
}

See stackblitz

Related