I'm working on writing a component intended to simplify/homogenize the way our forms look and interact. The code looks something like this:
Example Usage
...
<my-form-input labelKey = "email" controlName="emailAddress" [form]="userForm">
<input myInput class="form-control" type="email" formControlName="emailAddress" />
</my-form-input>
...
You can see that "emailAddress"
is passed to MyFormInputComponent
as the controlName
and is passed a second time to the FormControlName
directive on the <input>
element. I'd like to only pass this once so that my end user doesn't have to do this.
Is there a good way I can go about this, or is this just a constraint I should accept (if yes, an explanation of why this constraint exists would be welcome)? Code is shown below.
I've tried two approaches:
- Setting a
@HostBinding("attr.formControlName")
annotation in theMyInput
component. I can manipulate an attribute calledformcontrolname
on the element this way, but it doesn't trigger the directive that Angular Forms needs to properly register the control with the group. - Ask the user to supply
formControlName
to the<input>
element and read the value off of this for the rest of the component. This might work, but I'd have to access the DOM directly through anElementRef
, which is not recommended. The recommended route for interacting with DOM --Renderer
-- doesn't seem to expose any ability to read attributes either.
my-form-input.component.ts
@Component({
selector: 'my-form-input',
templateUrl: './my-form-input.component.html',
styleUrls: ['./my-form-input.component.scss']
})
export class MyFormInputComponent implements OnInit, AfterContentInit {
@Input()
labelKey: string;
@Input()
controlName: string;
@Input()
form: FormGroup;
@ContentChild(MyInputDirective)
input: MyInputDirective;
ngAfterContentInit(): void {
this.initInput();
}
/**
* Updates the input we project into the template
*/
private initInput() {
this.input.updatePlaceholder(this.labelKey);
// I'd like to somehow edit the FormControlName directive applied to the input here
}
}
my-form-input.component.html
<label>{{ labelKey | translate }}</label>
<ng-content></ng-content>
<my-input-error [control]="form.controls[controlName]" [name]="labelKey | translate" />
my-input.directive.ts
@Directive({
selector: '[myInput]'
})
export class myInputDirective implements OnInit {
private placeholderKey = "";
@HostBinding("placeholder")
private placeholder: string;
updatePlaceholder(placeholderKey: string) {
this.placeholderKey = placeholderKey;
this.placeholder = this.translateService.instant(this.placeholderKey);
}
constructor(private translateService: TranslateService) {
}
}
my-form-error.component.ts
// Not shown since not relevant.