cpaulus
cpaulus

Reputation: 284

Angular - Add component after another (in code)

I'm trying to build a re-sizable panels system with Angular. So you can have multiple containers separated with a bar that allow the user to resize them.

For the moment I have a solution that requires the developer to write this HTML code:

<split-pane>
    <container>Some content</container>
    <separator></separator>
    <container>Another content</container>
    <separator></separtor>
    <container>Content ?</container>
<split-pane>

split-pane, container and separator are all custom angular2 components. split-pane template is just

<ng-content></ng-content>

and I access container and separtor within split-pane using @ContentChildren(ContainerComponent) and @ContentChildren(SeparatorComponent)

The problem I have with this solution, is that the developper needs to manually add each separator between all containers.

I'd like to have a solution where the needed HTML would be :

<split-pane>
    <container>Some content</container>
    <container>Another content</container>
    <container>Content ?</container>
<split-pane>

And the separator components would be automatically added. But I don't know how to do this with Angular. Transclusion seems to be a way to approach this but I can't wrap my head around it.

Any idea ?

Thanks

Upvotes: 4

Views: 433

Answers (2)

Tatsuyuki Ishi
Tatsuyuki Ishi

Reputation: 4031

This doesn't match your desired syntax, but by using ngFor you may be able to make the code shorter.

Combine ngFor with last:

<template ngFor let-item [ngForOf]="items" let-i="index" let-last="last">
  <container>{{item.content}}</container>
  <separator *ngIf="!last"></separator>
</template>

Define items in the component class, so it can obtain the data.

Upvotes: 1

yurzui
yurzui

Reputation: 214017

If we need to load something dynamically therefore first of all we need to say angular compiler about our dynamic component like this:

  ...
  entryComponents: [SeparatorComponent]
})
export class AppModule {}

So our desired template looks like this:

 <split-pane>
   <container>Some content</container>
   <container>Another content</container>
   <container>Content ?</container>
 </split-pane>

In order to add something between container elements we should get ViewContainerRef for each of container. I would do it within SplitPaneComponent the following way

@ContentChildren(ContainerComponent, { read: ViewContainerRef }) containersRefs: QueryList<ViewContainerRef>;

Then just use ComponentFactoryResolver to get component factory and received above ViewContainers to add SeparatorComponent after container tag. Seems it should look like:

ngAfterContentInit() {
  this.containersRefs.forEach((vcRef: ViewContainerRef, index: number, arr: any[]) => {
    if(index === arr.length - 1) {
        return;
    }

    let compFactory = this.resolver.resolveComponentFactory(SeparatorComponent);
    let compRef = vcRef.createComponent(compFactory);
    this.separators.push(compRef);
  })
}

Plunker Example

Upvotes: 3

Related Questions