Injection of dynamic directive/component in Angular 2

1.7k Views Asked by At

I'm new to Angular 2 and thought I'd make an extendable master-detail flow to start learning.

The 'master'-part is working, I can easily plugin the specific service I need to populate the list when bootstrapping the app. The problem lies in making the 'detail'-part extendable.

Basically, the master-detail template has the following lines in the template:

<div class="large-10 columns">
    <detail [item]="masterItemActive" id="detail"></detail>
</div>

No, I could just load the Detail directive and be done with it, but I want that directive/component to be injectable so I could plugin whatever detail directive/component I like without hard-coding it into the 'master-detail'-component.

In order to achieve this I tried the DynamicComponentLoader:

dcl.loadAsRoot(detailComponent, '#detail', injector);

And the constructor of master-detail.component.ts:

constructor(
    dcl:DynamicComponentLoader,
    injector: Injector,
    elementRef:ElementRef,
    detailComponent:BaseDetailComponent

And as part of the bootstrap:

provide(BaseDetailComponent, {useValue: SomeSpecificDetailComponent})

The good news is that this works, it loads the SomeSpecificDetailComponent and shows the template where needed.

But now I'm stuck. Typescript is complaining, I cant seem to access the item passed down via <detail [item]='masterItemActive'> and I have no idea if this pattern is the way to go for finding a solution for this problem.

So my three questions are:

Is the DynamicComponentLoader the way to go to solve this problem?

Because I would much rather provide() a directive which the master-detail uses. This seems the most painless approach but I have no idea how to achieve this.

How can I access the item inside SomeSpecificDetailComponent?

I tried:

@Injectable()
export class SomeSpecificDetailComponent extends BaseDetailComponent {
    @Input()
    item:BaseMasterItem; // always empty (and yes, masterItemActive is being set )
}

And how can I prevent typescript from complaining?

Because the first argument of dcl.loadAsRoot() needs to be of type 'Type' - which it isn't.

Argument of type 'BaseDetailComponent' is not assignable to parameter of type 'Type'

Any help would be much appreciated!

Update

I've been wrongly using Type as an interface, the typescript compilation error was fixed by using BaseDetailComponent extends Type.

1

There are 1 best solutions below

4
On BEST ANSWER

Binding to dynamically injected components or directives is currently not supported.

What you can do is to pass the data imperatively to the created component

dcl.loadAsRoot(detailComponent, '#detail', injector)
.then(componentRef => componentRef.instance.item = this.masterItemActive);