Here is a working example with DI etc, it relies on ViewComponentRef.createComponent
with doesn't use the deprecated ComponentFactoryResolver
:
@Component({
selector: 'hello',
template: '<div #container></div>',
standalone: true,
})
export class HelloComponent implements OnInit {
@ViewChild('container', { read: ViewContainerRef, static: true })
container: ViewContainerRef;
constructor(
private injector: Injector,
private environement: EnvironmentInjector
) {}
ngOnInit() {
// runInContext is important to allow DI with inject()
this.environement.runInContext(() => {
const clazz = class {
private foo = inject(Foo); // From the local provider
private bar = inject(Bar); // From the global provider
public test;
constructor() {
this.test = 'some value';
console.log(this.foo.rand, this.bar.rand);
}
};
// Here is the trick to change the class name
Object.defineProperty(clazz, 'name', { value: 'TheName' });
// Define the component using Component decorator.
const component = Component({
selector: 'test',
template:
'<div>This is the dynamic template.<br> Test value: {{test}}</div>',
styles: [':host {color: red}'],
providers: [{ provide: Foo, useClass: Foo }],
})(clazz);
const componentRef = this.container.createComponent(component, {
injector: this.injector,
});
timer(0, 1000).subscribe((val) => {
componentRef.instance.test = val % 2 ? 'tic' : 'tac';
});
});
}
}
@Component({
selector: 'my-app',
template: 'This is static <hr> <hello></hello>',
standalone: true,
imports: [HelloComponent],
})
export class AppComponent {
name = 'Angular ' + VERSION.major;
}
@Injectable()
class Foo {
rand = Math.random();
}
@Injectable({ providedIn: 'root' })
class Bar {
rand = Math.random();
}
NB: Keep in mind that if you do this you'll pull the @angular/compiler
package in your main bundle increasing the side the said bundle. @angular/compiler
is stripped when you rely only on the AOT.
Stackblitz