I'm trying to create a custom control based on MatFormField. To start with, I went through the Angular Material documentation in the section on how to create your own custom control. An example from Angular Material I'm trying over:
https://material.angular.io/guide/creating-a-custom-form-field-control
From the documentation, you can jump to an example directly on Stackblitz.
I mean creating a completely new template, e.g. input, which will keep the styles from the Material, not wrapping the usual Material control - exact example in the link above.
According to the documentation, everything works fine. However, I am annoyed by the fact that every time I want to use such a control, I have to redefine <mat-form-field> etc. I tried in various ways to implement a wrapper for such a control, but to no avail.
I would like to create an identical control as in the example above, but with an additional wrapper of the "form-field-custom-control-example" component - I mean some wrapper for <mat-form-field> as a new component, which I can then call in the form template.
For example what I would like to achieve:
<form [formGroup]="form">
<form-field-custom-control-example [formControlName]="someControl"></form-field-custom-control-example>
</form>
I'm not even sure if I should also implement ControlValueAccessor on this wrapper and perhaps use references to refer to the methods of ControlValueAccessor which is defined in the nested control? Or maybe with @Input decorator itself pass formControl/formControlName?
I tried both approaches but maybe I made some mistakes along the way or approached the topic wrong.
Is there any dedicated solution for such a scenario or does anyone know a nice method to implement such a wrapper? I will be grateful for any tips and examples.
Generally you can use viewProvider in the way, e.g.
@Component({
selector: 'app-input',
template: `<h1>Hello </h1>
<input [formControlName]="name"/>
`,
styles: [`h1 { font-family: Lato; }`],
viewProviders:[{ provide: ControlContainer, useExisting: FormGroupDirective }]
})
export class HelloComponent {
@Input() name: string;
constructor(){}
}
And use the component like
<app-input name="control" > </app-input>
form=new FormGroup({
control:new FormControl()
})
But (And I don't know why) using mat-input not work :(. So we can use a work-around: inject in constructor the formGroupDirective and use ngAfterViewInit to reference the control to the FormControl of the formGroup
The component like
<form class="example-form">
<mat-form-field class="example-full-width">
<mat-label>Favorite food</mat-label>
<input matInput [formControl]="control" placeholder="Ex. Pizza" >
</mat-form-field>
</form>
control:FormControl
@Input() controlName=''
constructor(@Host() private parentF: FormGroupDirective) { }
ngAfterViewInit()
{
this.control=this.parentF.form.get(this.controlName) as FormControl
|| new FormControl()
}
And use
<form [formGroup]="form">
<input-overview-example controlName="control"></input-overview-example>
</form>
form=new FormGroup({
control:new FormControl()
})
See stackblitz