📖Browse Tutorials▼

Angular (v17+ Signals)

Angular 17+

Modern Angular leverages Standalone Components,Signals, and direct DOM injection via createComponent and ViewContainerRef. This guide covers clean, zero-boilerplate integration with Strelit UI Kit.

1. Installation

Add Strelit UI Kit to your Angular project dependencies:

npm install strelit-ui-kit

2. Standalone Docking Host Component

Create an Angular component that initializes Strelit and mounts standalone Angular components dynamically into Strelit containers:

import {
  Component,
  ElementRef,
  viewChild,
  OnInit,
  OnDestroy,
  ApplicationRef,
  createComponent,
  EnvironmentInjector,
  Type,
} from '@angular/core';
import { StrelitLayout, LayoutConfig, ComponentContainer } from 'strelit-ui-kit';
import { TelemetryPanelComponent } from './telemetry-panel.component';
import { LogStreamPanelComponent } from './log-stream-panel.component';

@Component({
  selector: 'app-docking-workspace',
  standalone: true,
  template: `<div #dockingContainer class="docking-viewport"></div>`,
  styles: [
    `
      .docking-viewport {
        width: 100vw;
        height: 100vh;
        overflow: hidden;
      }
    `,
  ],
})
export class DockingWorkspaceComponent implements OnInit, OnDestroy {
  private containerEl = viewChild.required<ElementRef<HTMLDivElement>>('dockingContainer');
  private layout?: StrelitLayout;

  private registry: Record<string, Type<any>> = {
    telemetry: TelemetryPanelComponent,
    logs: LogStreamPanelComponent,
  };

  constructor(
    private appRef: ApplicationRef,
    private injector: EnvironmentInjector
  ) {}

  ngOnInit() {
    const config: LayoutConfig = {
      root: {
        type: 'row',
        content: [
          {
            type: 'component',
            componentType: 'angularHost',
            title: 'Telemetry Inspector',
            componentState: { componentKey: 'telemetry' },
          },
          {
            type: 'component',
            componentType: 'angularHost',
            title: 'Event Log Stream',
            componentState: { componentKey: 'logs' },
          },
        ],
      },
    };

    // 1. Instantiate StrelitLayout directly on target element
    this.layout = new StrelitLayout(this.containerEl().nativeElement);

    // 2. Register dynamic Angular Component factory
    this.layout.registerComponentFactoryFunction(
      'angularHost',
      (container: ComponentContainer, itemConfig) => {
        const targetEl = container.element;
        const state = (itemConfig.componentState as { componentKey: string }) || {
          componentKey: '',
        };
        const ComponentClass = this.registry[state.componentKey];

        if (!ComponentClass) return;

        // Instantiate standalone component dynamically
        const compRef = createComponent(ComponentClass, {
          environmentInjector: this.injector,
          hostElement: targetEl,
        });

        this.appRef.attachView(compRef.hostView);

        // Clean up Angular component lifecycle when pane is closed
        container.on('destroy', () => {
          this.appRef.detachView(compRef.hostView);
          compRef.destroy();
        });
      }
    );

    // 3. Load layout configuration
    this.layout.loadLayout(config);
  }

  ngOnDestroy() {
    this.layout?.destroy();
  }
}

3. Reactive State with Angular Signals

Inside your standalone panels, you can use Angular Signals freely. State changes will re-render within their docked panel instantly without triggering unnecessary global change-detection cycles:

import { Component, signal, computed } from '@angular/core';

@Component({
  selector: 'app-telemetry-panel',
  standalone: true,
  template: `
    <div class="telemetry-box">
      <h4>Throughput: {{ throughput() }} req/s</h4>
      <p>Status: {{ statusLabel() }}</p>
      <button (click)="increment()">Simulate Traffic Spike</button>
    </div>
  `,
})
export class TelemetryPanelComponent {
  throughput = signal(1240);
  statusLabel = computed(() => (this.throughput() > 2000 ? 'High Load 🔥' : 'Nominal 🟢'));

  increment() {
    this.throughput.update((v) => v + 250);
  }
}

Looking for legacy AngularJS 1.x tutorials?

For historical projects maintaining AngularJS 1.x codebases with $scope, see our Simple AngularJS and Complex AngularJS guides in the Archival section.

Whether you are building complex multi-screen trading terminals, enterprise data workspaces, or migrating from legacy layout engines, our team and community are here to help.

Open an Issue on GitHub →