Reputation: 4954
I have this component in my template:
<vector-editor #scaleControl
[x]="scaleX"
[y]="scaleY"
[z]="scaleZ" >
</vector-editor>
The vector-editor
has the following structure:
export class VerticeControlComponent implements OnInit
{
@Input() x: number;
@Input() y: number;
@Input() z: number;
...
}
In my application I grab a reference to the #scaleControl
using
@ViewChild('scaleControl') scaleControl: ElementRef;
Now if I output scaleControl
to the console I get this result:
As can be seen, the reference is not null and all the properties of my component are there. I want to access those properties, but in code the actual type of the scaleControl
is ElementRef
and not VectorEditorControl
as seen in the output. Because of this, TypeScript doesn't me allow to use this.scaleControl.x
.
I also tried to cast ElementRef
like this
var temp = <VectorEditorControl>this.scaleControl
but I get an error telling me that I cannot cast ElementRef
to VectorEditorControl
In the end, I tried to access this.scaleControl.nativeElement
but it's undefined...
What am I missing here?
Upvotes: 59
Views: 105073
Reputation: 3966
At the time of writing I recommend using the following method:
@ViewChild('scaleControl') scaleControl: ElementRef<VerticeControlComponent>;
You can then have access to both the types.
scaleControl
scaleControl.nativeElement
Upvotes: 7
Reputation: 214017
You should know the following things about using @ViewChild property decorator.
It uses the following Metadata Properties:
From source code:
export interface ViewChildDecorator {
/**
* You can use ViewChild to get the first element or the directive matching
* the selector from the
* view DOM. If the view DOM changes, and a new child matches the selector,
* the property will be updated.
*
* View queries are set before the `ngAfterViewInit` callback is called.
*
* **Metadata Properties**:
*
* * **selector** - the directive type or the name used for querying.
* * **read** - read a different token from the queried elements.
*/
(selector: Type<any>|Function|string, {read}?: {read?: any}): any;
new (selector: Type<any>|Function|string, {read}?: {read?: any}): ViewChild;
}
If you don't provide the read
parameter, @ViewChild()
will return the:
ElementRef
instance if there is no component appliedSo if you want to get ElementRef
from the child that is angular2 component (VerticeControlComponent
) you need to explicitely tell using read: ElementRef
:
@ViewChild('scaleControl', {read: ElementRef}) scaleControl: ElementRef;
And then inside ngAfterViewInit hook or later you can write this.scaleControl.nativeElement
to get DOM element.
I wrote early:
- different token from the queried elements if you set read property
Now I want to add what exactly we can read:
ElementRef
TemplateRef
ViewContainerRef
Provider
What does Provider
mean here?
It means that if we defined any provider(in component or directive) on specific element then we can read it.
@Component({
selector: 'child',
template: `
<h2>I'm child</h2>
`,
providers: [
{
provide: 'test', useValue: 'x'
}
]
})
export class ChildComponent {
}
So in consumer of this component we can write
@ViewChild(ChildComponent, { read: 'test' }) providerToken: string;
to get value x
.
See also:
Upvotes: 126
Reputation: 71
I got this error two times. Once in my main code and second time in the test code (spec).
Both time it was some reference missing. Angular compiler(transpiler) does not show any error during compilation but later on, quietly does not provide reference of the
First time I got this error in the main code abc.component.ts. I remember that this time, we included the references required for this child correctly in this abc.component.ts. This child component was coming from another module. The error was resolved only after this child component was not included in the module.ts file
declarations: [VectorEditorComponent,....],
Second time we faced this in spec file. I was trying to verify some expectation that a property of the child component should be set. I was not getting instance of the child component but getting ElementRef instead. Here again, there was no compilation error. The problem was slightly different here. I had used No_Errors_Schema. So, although we had not included the component in the spec file, angular did not complain, but instead set ElementRef instead of the child component. The error went away when we imported the module and provided this in the testbed setup of the spec file.
In the second case I can understand that it was due to no error schema. But in the first case, I think Angular team needs to improve. There is no hint whatsoever about why component was not provided but ElementRef is provided.
Upvotes: 1