I've been building a component library for angular which contains an accordion and offcanvas component. I've created a minimal StackBlitz with a demo.
Now I want to be able to preserve the expanded states of the accordion in the sidebar. Currently, when showing the sidebar, and expanding multiple accordions, when you close and reopen the sidebar all accordions are collapsed again.
The offcanvas is shown with the following code snippet:
const injector = Injector.create({
providers: [{ provide: 'OFFCANVAS_CONTENT', useValue: template }],
parent: this.parentInjector
});
// Portal which will hold the offcanvas component
const portal = new ComponentPortal(BsOffcanvasComponent, null, injector);
// Create overlay to the left side of the screen
const overlay = this.overlayService.create({
scrollStrategy: this.overlayService.scrollStrategies.reposition(),
positionStrategy: this.overlayService.position().global()
.centerVertically().left('0'),
height: '100%',
hasBackdrop: true
});
// Instantiate the offcanvas. This will resolve the provider,
// and render the template in the bootstrap 5 offcanvas
const componentInstance = overlay.attach<BsOffcanvasComponent>(portal);
The code renders the template passed through the OFFCANVAS_CONTENT
provider inside the OffcanvasComponent with the following template:
<div class="offcanvas overflow-hidden" [class]="offcanvasClass$ | async"
[class.show]="show$ | async"
[class.h-100]="offcanvasHeight100$ | async"
[style.height.px]="size"
[class.oc-max-width]="['start', 'end'].includes(position)"
[class.oc-max-height]="['top', 'bottom'].includes(position)">
<ng-container *ngTemplateOutlet="content; context: { $implicit: this }" ></ng-container>
</div>
In the example I'm rendering an AccordionComponent inside the overlay's template:
<body>
<button (click)="toggleSidebar(sidebarTemplate)">Toggle sidebar</button>
<ng-template #sidebarTemplate let-offcanvas>
<app-sidebar></app-sidebar>
</ng-template>
</body>
But since I'm creating a new component instance based on a TemplateRef
each time the offcanvas is shown, the state of the components inside the sidebar is lost again.
How can I circumvent this? It seems impossible to render a component instance inside a CDK overlay, you can only render a template inside a CDK overlay.
I took another approach here, and decided to render the
TemplateRef
in the CDKOverlay
in theAfterViewInit
hook (so right after the host component is created/rendered). I now do this only once, so the entire state of whatever's inside the CDKOverlay
is preserved.Other than that, it's just a matter of responding to changes in the
Input
bindings.StackBlitz demo
Old solution
Solved this by creating 2 directives that persist the active tab in a field on the
AppComponent
.from-overlay
from-overlay-id