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
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);
})
}
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.