Reputation: 5040
Creating a component like below
<div class="test-search-field"
[ngClass]="{'expanding': expanding}">
<ng-content></ng-content>
</div>
The user of this component will add an input
element while using this component.
<my-input-container>
<input type="search" placeholder="Search">
</my-input-container>
From the component I want to get hold of this input element, but getting errors while querying using @ContentChild
.
@ContentChild('input') inputElemRef: ElementRef;
ngAfterContentInit() {
setInterval(() => {
console.log(this.inputElemRef);
}, 2000);
But this inputElemRef
is always coming undefined.
Can anyone please tell me what mistake I am doing here.
Upvotes: 3
Views: 5865
Reputation: 16837
my-input.directive.ts
import { Directive } from '@angular/core';
@Directive({
selector: '[myInput]',
})
export class MyInputDirective {}
my-input-container.component.ts
import { Component, Input, ContentChild, AfterContentInit, ElementRef } from '@angular/core';
import { MyInputDirective } from './my-input.directive';
@Component({
selector: 'my-input-container',
template: `<ng-content></ng-content>`,
styles: [`h1 { font-family: Lato; }`]
})
export class MyInputContainerComponent implements AfterContentInit {
@ContentChild(MyInputDirective, { read: ElementRef }) child: MyInputDirective;
ngAfterContentInit() {
console.log(this.child);
}
}
usage:
<my-input-container>
<input myInput />
</my-input-container>
If you only care about the ElementRef, you can skip the custom directive entirely, and query by the template variable instead.
my-input-container.ts
import { Component, Input, ContentChild, AfterContentInit, ElementRef } from '@angular/core';
@Component({
selector: 'my-input-container',
template: `<ng-content></ng-content>`,
styles: [`h1 { font-family: Lato; }`]
})
export class MyInputContainerComponent {
@ContentChild('myInput') child: ElementRef;
ngAfterContentInit() {
console.log(this.child);
}
}
usage:
<my-input-container>
<input #myInput />
</my-input-container>
In general the first option is preferrable and its what the @angular/material
does with their input component. They pair the container component (mat-form-field
) with a directive applied to the native input element (matInput
).
It is more flexible, because you can query either for the Directive, or for the ElementRef.
@ContentChild(MyInputDirective) child: MyInputDirective;
@ContentChild(MyInputDirective, { read: ElementRef }) child: MyInputDirective;
Upvotes: 7
Reputation:
I would have used the renderer to do that.
Somethin like this stackblitz
ngAfterViewInit() {
const el = this.renderder.selectRootElement('input');
console.log(el);
}
Upvotes: 2