Reputation: 56966
I have a form label in one component and its associated reusable custom input in a separate component. I have designed it like this because sometimes I want a label with the custom input and sometimes I don't. Sometimes I want the label to be above the custom input and sometimes I want it inline with the custom input. Thus separate components makes sense. It looks something like this (although the markup in the parent component may vary):
component1.component.html:
<label for="myInput">Label Text</label>
<app-component2></app-component2>
component2.component.html
<input id="myInput" ... loads of custom stuff here>
The only problem is that the label for
and input id
does not work. When I click the label it does not select the input when the input is in another component. How can I make it work?
Thanks
Upvotes: 1
Views: 914
Reputation: 1266
You can relay the id attribute by reading the id as an @Input
, rendering it to the form element in the template, and then removing it from the host element (as html ids need to be unique) once the template is initiated.
export class Component2 implements AfterContentInit {
@Input() id: string;
constructor(
private readonly _elementRef: ElementRef,
private readonly _renderer: Renderer2
) {}
ngAfterContentInit(): void {
// or rewrite it to another non-unique attribute
this._renderer.removeAttribute(this._elementRef.nativeElement, 'id');
}
}
And in the Component2 template
<input id="{{id}}">
This allows Component1 to use the selector of Component2 as if it was an input element.
<label for="myInput">Label Text</label>
<app-component2 id="myInput"></app-component2>
Upvotes: 1
Reputation: 56966
I got this working by doing this:
<label>
<span>Label Text</span>
<app-component2></app-component2>
</label>
where app-component2 contains the input element.
Upvotes: 1
Reputation: 47
You can wrap up both the components into a parent component and can pass the required id by emitting a event by on click of the label into the
Your code will be like
Parentcomponent.html
<parentComponent>
<component1 (emitId) ='setLabelId($event)'></component1>
<component2 [labelId]='labelId'></component2>
</parentComponent>
and parentComponent.ts will be
export class parentComponent implements OnInit {
const labelId : string;
constructor() { }
ngOnInit() {
}
setLabelId(id:string){
this.labelId = id;
}
}
and component1.ts will be like
export class Component1 implements OnInit {
@Output() emitId = new EventEmitter<string>();
constructor() { }
ngOnInit() {
}
handleLabelClick(id:string){
this.emitId.emit(id);
}
}
component1.html
<label onClick="handleLabelClick(myInput)" for="myInput">
where component2.ts will be like
export class Component2 implements OnInit {
@Input() labelId:string
constructor() { }
ngOnInit() {
// this.labelId holds the value of required id
}
}
and component2.html
<input id="myInput" ... loads of custom stuff here>
Upvotes: 1