angular: lazy load from ngComponentOutlet is broken after v12
Bug Report
Affected Package
The issue is caused by package @angular/coreIs this a regression?
Yes, the previous version in which this bug was not present was: v11Description
We have this lazy components that loads using *ngComponentOutlet
directive in v11 but after upgrade to v12, the same code didn’t worked as it displays errors like
Can't bind to 'ngIf' since it isn't a known property
or
The pipe 'async' could not be found!
etc., I think this is because of the common module isn’t get referenced.
Minimal Reproduction
I have created this stackblitz repo so just open the console and you’ll see the issues.
If you downgrade it into v11, the same code works.
// alzy-two component
@Component({
selector: 'app-lazy-2',
template: `
<h4>loading lazy level 2</h4>
`
})
export class LazyTwoComponent {}
// lazy-two module
import { LazyTwoComponent } from './lazy-two.component';
@NgModule({
imports: [CommonModule],
declarations: [LazyTwoComponent]
})
export class LazyTwoModule {}
// lazy one
import { LazyTwoComponent } from '../lazy2/lazy-two.component';
@Component({
selector: 'app-lazy-1',
template: `
<h1 *ngIf="title">{{title}}</h1>
<ng-template [ngIf]="lazyComp | async">
<ng-container *ngComponentOutlet="lazyComp | async"></ng-container>
</ng-template>
`
})
export class LazyOneComponent implements AfterViewInit {
title = 'hello from one'
lazyComp: Promise<Type<LazyTwoComponent>>
ngAfterViewInit(){
this.lazyComp = import('../lazy2/lazy-two.component')
.then(({LazyTwoComponent})=> LazyTwoComponent)
}
}
// lazy-one.module
import { LazyOneComponent } from './lazy-one.component';
@NgModule({
imports: [CommonModule],
declarations: [LazyOneComponent]
})
export class LazOneModule {}
// app.ts
import { LazyOneComponent } from './components/lazy1/lazy-one.component';
@Component({
selector: 'my-app',
template`<ng-container *ngComponentOutlet="lazyComp | async"></ng-container>`
})
export class AppComponent implements AfterViewInit {
lazyComp: Promise<Type<LazyOneComponent>>
ngAfterViewInit(){
this.lazyComp = import('./components/lazy1/lazy-one.component').then(({LazyOneComponent}) => LazyOneComponent)
}
}
// app.module
import { AppComponent } from './app.component';
@NgModule({
imports: [CommonModule, BrowserModule],
declarations: [ AppComponent],
bootstrap: [ AppComponent ]
})
export class AppModule { }
Exception or Error
NG0303: Can't bind to 'ngIf' since it isn't a known property of 'h1'.
NG0302: The pipe 'async' could not be found!.
Your Environment
Angular Version:
@angular-devkit/architect 0.1201.0
@angular-devkit/build-angular 12.1.0
@angular-devkit/core 12.1.0
@angular-devkit/schematics 12.1.0
@schematics/angular 12.1.0
rxjs 6.6.7
typescript 4.3.4
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 21 (13 by maintainers)
@irowbin Sure, but the main point is that the Angular compiler must understand that such a module should be taken into account. That’s why there should be something that did it in your case, and it’s not clear what it was.
Netanel Basal’s article uses the variant of a single file for declaring a component and its module.
@irowbin The logic is the same in v11 and v12. As I know, there is no difference between both versions.
This appears to be working as expected. If the
lazy-one.module.ts
file is never imported from anywhere, the compiler won’t be aware of its existence depending on the TypeScript configuration. You’ll typically see something like"files": ["src/index.ts"]
intsconfig.app.json
which means that a single file is included which will then pull in additional files as they are discovered throughimport
statements. I suspect that in v11 this was configured differently, e.g. using anincludes
rule intsconfig.app.json
, such that thelazy-one.module.ts
was part of the compilation and therefore made the list of declarations available toLazyOneComponent
.