core/split-view/split-view.component.ts
A responsive split view layout component with automatic selection management and resizable panes.
export class MyComponent {
items: Device[] = [];
selectedItem?: Device;
onSelectionChange(item: Device | null) {
this.selectedItem = item || undefined;
}
}<c8y-sv (selectionChange)="onSelectionChange($event)">
<c8y-sv-list [title]="'Devices'">
<c8y-sv-header-actions>
<button class="btn btn-primary">Add Device</button>
</c8y-sv-header-actions>
@for (item of items; track item.id) {
<c8y-li [c8ySvListItem]="item">
{{ item.name }}
</c8y-li>
}
<c8y-sv-footer>
Total: {{ items.length }}
</c8y-sv-footer>
</c8y-sv-list>
<c8y-sv-details
emptyStateIcon="c8y-devices"
emptyStateTitle="No device selected"
emptyStateSubtitle="Select a device to view details">
@if (selectedItem) {
<c8y-sv-extra-header>
<c8y-icon-panel [sections]="sections"></c8y-icon-panel>
</c8y-sv-extra-header>
}
@if (selectedItem) {
<h3>{{ selectedItem.name }}</h3>
<p>{{ selectedItem.description }}</p>
}
</c8y-sv-details>
</c8y-sv>For components using Angular router:
Example :<c8y-sv>
<c8y-alarms-list>...</c8y-alarms-list>
<c8y-sv-details (backClick)="handleBackClick()">
<router-outlet></router-outlet>
</c8y-sv-details>
</c8y-sv>async handleBackClick(): Promise<void> {
await this.alarmsViewService.closeDetailsView(this.activatedRoute);
}<c8y-sv
[isResizable]="true"
[resizableBreakpoint]="991"
[resizableConfig]="{
trackId: 'my-split-view',
leftColumnWidth: '40%',
collapseThreshold: 320,
collapsible: false
}"
[initialSelection]="items[0]"
(selectionChange)="onSelectionChange($event)">
<!-- content -->
</c8y-sv>Omit <c8y-sv-details> for a simple list view:
<c8y-sv>
<c8y-sv-list [title]="'Items'">
@for (item of items; track item.id) {
<c8y-li>{{ item.name }}</c8y-li>
}
</c8y-sv-list>
</c8y-sv>
| providers |
SplitViewSelectionService
|
| selector | c8y-sv |
| standalone | true |
| imports |
C8yTranslatePipe
|
| templateUrl | ./split-view.component.html |
CommonModule
RouterOutlet
C8yTranslatePipe
ResizableGridComponent
SplitViewSelectionService
OnInit
OnDestroy
<div
[attr.aria-label]="'Split view interface' | translate"
tabindex="-1"
role="main"
[ngClass]="getContainerClasses()"
data-cy="c8y-sv"
>
@if (shouldUseResizableGrid) {
<c8y-resizable-grid
[collapseThreshold]="effectiveResizableConfig.collapseThreshold"
[collapsible]="effectiveResizableConfig.collapsible"
[leftColumnWidth]="effectiveResizableConfig.leftColumnWidth"
[trackId]="effectiveResizableConfig.trackId"
>
<div left-pane>
<ng-container *ngTemplateOutlet="listContent"></ng-container>
</div>
<div right-pane>
<ng-container *ngTemplateOutlet="detailsContent"></ng-container>
</div>
</c8y-resizable-grid>
} @else {
<ng-container *ngTemplateOutlet="listContent"></ng-container>
<ng-container *ngTemplateOutlet="detailsContent"></ng-container>
@if (showDefaultRouterOutlet && !hasProjectedDetails) {
<router-outlet class="d-contents"></router-outlet>
}
}
<ng-template #listContent>
<ng-content select=":not(c8y-sv-details)"></ng-content>
</ng-template>
<ng-template #detailsContent>
@if (hasProjectedDetails) {
<ng-content select="c8y-sv-details"></ng-content>
}
</ng-template>
</div>