I can't get angular's DynamicComponentLoader to work in beta.6
I've taken the example code for dynamic component loading from their docs, and added it to their working starter code in plnkr, see here.
Here's the code:
import {Component, DynamicComponentLoader, ElementRef} from 'angular2/core';
@Component({
selector: 'child-component',
template: 'Child'
})
class ChildComponent {
}
@Component({
selector: 'my-app',
template: '<h1>My First Angular 2 App</h1><div #child></div>'
})
export class AppComponent {
constructor(dcl: DynamicComponentLoader, elementRef: ElementRef) {
dcl.loadIntoLocation(ChildComponent, elementRef, 'child');
}
}
And here is the stacktrace, which says: "There is no component directive at element":
EXCEPTION: Error during instantiation of AppComponent!.BrowserDomAdapter.logError @ angular2.dev.js:23083
angular2.dev.js:23083 ORIGINAL EXCEPTION: There is no component directive at element [object Object]BrowserDomAdapter.logError @ angular2.dev.js:23083
angular2.dev.js:23083 ORIGINAL STACKTRACE:BrowserDomAdapter.logError @ angular2.dev.js:23083
angular2.dev.js:23083 Error: There is no component directive at element [object Object]
at new BaseException (angular2.dev.js:7351)
at AppViewManager_.getNamedElementInComponentView (angular2.dev.js:6441)
at DynamicComponentLoader_.loadIntoLocation (angular2.dev.js:12375)
at new AppComponent (run.plnkr.co/mk31ybnwEtsiX31r/app/app.component.ts!transpiled:33)
at angular2.dev.js:1420
at Injector._instantiate (angular2.dev.js:11459)
at Injector._instantiateProvider (angular2.dev.js:11395)
at Injector._new (angular2.dev.js:11385)
at InjectorInlineStrategy.instantiateProvider (angular2.dev.js:11149)
at ElementDirectiveInlineStrategy.init (angular2.dev.js:9081)BrowserDomAdapter.logError @ angular2.dev.js:23083
angular2.dev.js:23083 ERROR CONTEXT:BrowserDomAdapter.logError @ angular2.dev.js:23083
angular2.dev.js:23083 _ContextcomponentElement: nullelement: my-appinjector: Injector__proto__: _ContextBrowserDomAdapter.logError @ angular2.dev.js:23083
angular2-polyfills.js:1152 DEPRECATION WARNING: 'dequeueTask' is no longer supported and will be removed in next major release. Use removeTask/removeRepeatingTask/removeMicroTask
DynamicComponentLoader is being deprecated (see commit). Now the correct way is to use ViewContainerRef
and ComponentResolver
(see update 3 below) for an example in the constructor.
In beta.1 there was a breaking change. You can't access anymore the view in the constructor. So you can move that example to ngOnInit() and it will work.
Quoting from the changelog
Component view is not yet created when component constructor is called. -> use onInit lifecycle callback to access the view of a component
export class AppComponent {
constructor(private dcl: DynamicComponentLoader, private elementRef: ElementRef) {
}
ngOnInit() {
this.dcl.loadIntoLocation(ChildComponent, this.elementRef, 'child');
}
}
Check this plnkr with your example working.
Just for your information I've sent a PR (see #7186) to fix the examples in the source code. So hopefully they will review it and it will pass.
Since beta.16 loadIntoLocation
was removed and the error is no longer reproducible. loadNextToLocation
now takes a ViewContainerRef
. I opened a new PR (see #8241) to add a new example of it, everything else is already covered by the original PR.
Code example (update 3)
As mentioned above now there's no loadIntoLocation
but the same behavior is achieved by using ViewContainerRef
and ComponentResolver
.
constructor(cmpResolver: ComponentResolver, viewContainer: ViewContainerRef) {
cmpResolver.resolveComponent(MyComponent)
.then((factory: ComponentFactory) => {
viewContainer.createComponent(factory, 0, viewContainer.injector)
});
}
Reference
ViewContainerRef#createComponent
ComponentResolver#resolveComponent
Regarding loadNextToLocation
, there are two ways, both use ViewContainerRef
.
ViewContainerRef
from the element itselfconstructor(private dcl: DynamicComponentLoader, viewContainer: ViewContainerRef) {
dcl.loadNextToLocation(MyComponent, viewContainer).then(ref => {});
}
// Assume the next view
template : '<div #container></div>';
class MyClass {
@ViewChild('container', {read: ViewContainerRef}) container : ViewContainerRef;
constructor(private dcl: DynamicComponentLoader) {}
ngAfterViewInit() {
this.dcl.loadNextToLocation(MyDynamicCmp, this.container).then(ref => {});
}
}
A plnkr with the example above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With