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.