Component Queries Metadata Appears To Be Broken When The Ivy Renderer Is Enabled In Angular 9.0.0-rc.2
UPDATE - 2019-11-17: The @Component()
.queries
metadata appears to work if the --prod
flag is enabled. As such, this works for a production build; but, it doesn't work in the development server. So, perhaps this is actually a bug in the dev server, not in Ivy?
The other day, I thought I was taking crazy pills! No matter what I did, I couldn't get my ViewChild
Component template query to work in Angular 9.0.0-rc.2 if the query was defined in the @Component()
decorator. However, if I used a @ViewChild()
property decorator instead, it worked. Seeing as I rather dislike property decorators, this predicament was quite off-putting. After some trial-and-error, I finally figured out that the @Component()
decorator queries only failed if the Ivy rendered was enabled.
To see this in action, consider this App component that uses both forms of ViewChild
query annotations:
// Import the core angular services. | |
import { Component } from "@angular/core"; | |
import { ElementRef } from "@angular/core"; | |
import { ViewChild } from "@angular/core"; | |
// ----------------------------------------------------------------------------------- // | |
// ----------------------------------------------------------------------------------- // | |
@Component({ | |
selector: "app-root", | |
queries: { | |
divRefOne: new ViewChild( "divRef" ) | |
}, | |
styleUrls: [ "./app.component.less" ], | |
template: | |
` | |
<div #divRef> | |
As you wish..... | |
</div> | |
` | |
}) | |
export class AppComponent { | |
// Injected via @Component.queries. | |
public divRefOne!: ElementRef; | |
@ViewChild( "divRef" ) | |
public divRefTwo!: ElementRef; | |
// --- | |
// PUBLIC METHODS. | |
// --- | |
// I get called once after view bindings have been initialized. | |
public ngAfterViewInit() : void { | |
console.group( "DivRefOne : @Component( .queries )" ); | |
console.log( this.divRefOne ); | |
console.groupEnd(); | |
console.group( "DivRefTwo : @ViewChild()" ); | |
console.log( this.divRefTwo ); | |
console.groupEnd(); | |
} | |
} |
As you can see, divRefOne
defines the query in the @Component()
.queries
metadata while divRefTwo
defines the query using the @ViewChild()
property decorator.
Now, if we run this with Ivy enabled in Angular 9.0.0-rc.2, we get the following output:

As you can see, the ElementRef
for the @Component()
query is undefined
, even after the View Template has been initialized.
Now, if we run this with Ivy disabled in Angular 9.0.0-rc.2, we get the following output:

As you can see, the ElementRef
for the @Component()
query is valid. And, the only change that we made to this version of the Angular application is that we disabled Ivy.
ASIDE: I know that there were recent changes to the way the
ViewChild()
annotation can be defined. However, this same behavior is also exhibited withViewChildren()
, which has not had any recent changes.
Unless someone can explain why this is happening, this appears to be a bug in the way the Ivy renderer works in Angular 9.0.0-rc.2. I can't find any open Issues relating to this in the Angular GitHub, so I will try to open one shortly.
@Component()
metadata.
Epilogue On To me, the "metadata" for a Component is separate from the logic of the Component. As such, I find it confusing to have metadata and decorators scattered throughout the component definition. Instead, I love to see all of the metadata gathered neatly at the top (in the @Component()
decorator) so that I don't have to search for it. This way, when I want to see "How the component works", I look at the logic; and, if I want to see "How Angular interacts with the component", I look at the top in the @Component()
decorator. These are two different concerns and - in my opinion - should be somewhat isolated.
This is just my opinion. Your mileage may vary.
Want to use code from this post? Check out the license.
Reader Comments
@All,
To my surprise, my demo actually worked when I pushed it to GitHub pages. The only difference there is that I'm using the
--prod
flag when doing the build (as opposed to using the dev-server locally). I've added a note to the top of the blog post. So, perhaps this is a bug in the way Ivy interacts with the dev-server? This is clearly at a much lower-level than I can understand. I don't really even know how the dev-server is working.@All,
For completeness, here's my
package.json
(currently installed Angular 9.0.0-rc.2:And, here's my
tsconfig.json
:@All,
I've created an isolated repository in case anyone else wants reproduce:
https://github.com/bennadel/Component-Queries-Ivy-Bug-Angular9
@All,
It looks like it was a problem with my
angular.json
configuration. For reasons I don't fully understand (read: not at all), it seems that it was breaking because I didn't have theaot
(ahead of time) compiling setting in the base build configuration. Jeffrey Bosch figured it out, and I was able to get my proof-of-concept repo working.@All,
So, I just installed a fresh app on Angular 9.0.1 stable, and the same problem still exists.
ViewChildren
just seems to be broken until you move theaot
option to the main options, not thebuild
options. I don't get it.I'm having the same problem with unit tests. It works when I use decorators but not when I use the
queries
component metadata property. I'm guessing this is due to the component mocks being created dynamically so they can't benefit from AoT compilation on the first pass.@StupidAwesome,
Sorry you're running into this also; but, at the same time, I'm glad I'm not the only one.