SeatLayerSeatManagerComponent from @seatlayer/angular/manager puts the live
control room inside your Angular app. It is a standalone component over the
SeatManager class in @seatlayer/js/manager: the
same board, the same tools, the same token rules. This page covers what is
different in Angular. Read the control-room guide
for the board itself.
Available from @seatlayer/angular 0.106.0. Angular 17 or newer.
Import it from the manager entry
import { SeatLayerSeatManagerComponent } from "@seatlayer/angular/manager";The component is not exported from the package root. /manager is a separate
entry point that holds the control room and nothing else, so a buyer page that
imports @seatlayer/angular stays the same size, and a control room does not
carry the buyer picker.
Mount the board
Your backend mints a short-lived, event-scoped mse_ token after it checks
that the signed-in user may manage the event. Never put an sk_ secret key in
browser code. Keep the token in memory, never in a URL, browser storage, or
logs.
import { Component, Input } from "@angular/core";
import {
SeatLayerSeatManagerComponent,
type SeatManagerMode,
type SeatManagerOpenOrder,
type SeatManagerRoomState,
} from "@seatlayer/angular/manager";
@Component({
selector: "app-control-room",
standalone: true,
imports: [SeatLayerSeatManagerComponent],
template: `
<seatlayer-seat-manager
#room
eventKey="<YOUR_EVENT_KEY>"
[token]="session.token"
[tokenExpiresAt]="session.expiresAt"
[onTokenRefresh]="mintManageSession"
[(mode)]="mode"
(roomStateChange)="onRoomState($event)"
(openOrder)="openOrder($event)"
(errored)="showOperatorError($event)"
style="height: calc(100vh - 96px)"
/>
<button (click)="room.showObjects(['A-2', 'A-3'], 'Resale')">Show resale seats</button>
`,
})
export class ControlRoomComponent {
@Input({ required: true }) session!: { token: `mse_${string}`; expiresAt: number };
mode: SeatManagerMode = "view";
// An arrow function, so the board can call it without losing `this`.
mintManageSession = async () => {
const next = await fetch("/api/events/<YOUR_EVENT_KEY>/manage-session", {
method: "POST",
}).then((response) => response.json());
return { token: next.token, expiresAt: next.expiresAt };
};
onRoomState(state: SeatManagerRoomState) {
console.log("room is", state);
}
openOrder(order: SeatManagerOpenOrder) {
// Route to your own order page.
}
showOperatorError(error: unknown) {
console.error(error);
}
}The element is display: block; give it a real height and the board fills
it. The board is destroyed when Angular destroys the component.
Inputs
The inputs are the constructor options
without container. Live inputs change the running board in place: the
camera, selection, live connection and DOM stay. Read once inputs are read
when the board is built. Changing eventKey or apiBase builds a new board.
| Input | When it applies |
|---|---|
eventKey, apiBase |
Changing either builds a new board |
token, tokenExpiresAt |
Live |
onTokenRefresh |
Live. A function input that returns the new token |
capabilities |
Live |
currency |
Live |
theme |
Live |
themeMode |
Applied before the first paint, then live |
keepLiveWhileHidden |
Live |
mode |
Live. Use [(mode)] to follow the operator’s tool |
followLive |
Live. Use [(followLive)] to follow the operator’s choice |
selectableObjects, unavailableObjectsSelectable |
Live |
unavailableObjects, unavailableObjectsReason |
Live |
categoryPrices |
Live |
maxSelectedObjects, numberOfPlacesToSelect |
Live |
isObjectSelectable |
Live |
sale |
Live, compared by value |
mapInsets |
Live, compared by value |
tools, chrome |
Read once |
selectedObjects |
Read once |
kpis |
Read once. false when your own header shows the numbers |
timeZone |
Read once |
organizationName |
Read once |
colourBy |
Read once |
focusSection, focusSeat, focusSeats, focusCategory |
Read once |
arrivedFrom |
Read once. Its back.go() runs inside the Angular zone |
“Compared by value” means a new object with the same fields does nothing, so a
template can build sale or mapInsets inline without repainting the board on
every change detection.
Outputs
| Output | Payload |
|---|---|
(ready) |
none |
(tallies) |
SeatManagerTallies |
(activity) |
SeatManagerActivity |
(controlRoom) |
ControlRoomSnapshot |
(modeChange) |
SeatManagerMode |
(followLiveChange) |
boolean |
(selectionChange) |
ExpandedSeat[] |
(objectSelected), (objectDeselected) |
ExpandedSeat |
(selectionValidityChange), (selectionValid), (selectionInvalid) |
SeatManagerSelectionValidity |
(selectionLimit) |
number |
(filteredSectionChange) |
SeatManagerFilteredSection[] |
(areaClick) |
SeatManagerArea |
(actionComplete) |
SeatManagerActionResult |
(connectionChange) |
SeatManagerConnection |
(roomStateChange) |
SeatManagerRoomState: connecting, live, paused, offline or ended |
(errored) |
unknown |
(openOrder) |
SeatManagerOpenOrder: { id, displayRef } |
(openTrend) |
SeatManagerOpenTrend: { kpi, sectionId? } |
(openDesigner) |
none. Bind it and Sections on a chart without sections offers “Open the designer” |
The board offers “Open order” and the trend link only when you bind
(openOrder) or (openTrend), so it never shows a link that goes nowhere.
The board checks this when it is built.
(errored) rather than (error), as on the seating chart: error collides
with the native DOM error event on the host element.
Zone behaviour
The board runs a render loop, timers and a live connection. They run outside
the Angular zone, so they do not schedule change detection for your whole app.
Each output, onTokenRefresh and arrivedFrom.back.go() re-enter the zone, so
your handlers, HttpClient calls and router navigation behave as usual.
Template ref
A template ref (#room) has the same methods as the React handle:
| Method | Result |
|---|---|
setMode(mode) |
Switch tool |
setToken(token, expiresAt?) |
Rotate the token without a rebuild |
setHeatOverlay(enabled), setFollowLive(enabled) |
Toggle the overlay or camera following |
setTrendWindow(minutes) |
Refresh and return the control-room snapshot |
enterFullscreen(), exitFullscreen(), isFullscreen() |
Fullscreen |
block(labels?, { releaseAt?, reason? }), unblock(labels?), unblockAll() |
Block or unblock inventory |
cancelBooking(labels, bookingRef) |
Cancel by booking reference |
setCategory(categoryKey, labels?), setTableBooking(tableIds, mode, bounds?) |
Event-only category and table changes |
selectAll(), selectSection(id), selectByLabels(labels) |
Select seats |
selectObjects(labels), deselectObjects(labels) |
Custom selection by label |
selectCategories(keys), deselectCategories(keys) |
Custom selection by category |
setSelectableObjects, setUnavailableObjectsSelectable, setUnavailableObjects, setCategoryPrices, setObjectSelectable, setMaxSelectedObjects, setNumberOfPlacesToSelect |
The live inputs, called directly |
getSelectionValidity() |
Exact-count state, or null |
setFilteredSection(label), clearFilteredSection(), getFilteredSections() |
Section filter |
focusSection(label) |
Frame matching sections without filtering |
clearSelection(), getSelection() |
Selection |
getReport(), getControlRoomSnapshot(minutes?), getLog({ limit?, before? }) |
Reports and audit log |
setHoldTtl(msOrNull) |
Set or clear the event checkout window |
getConnection() |
Live link state, or null before the board exists |
zoomToFit() |
Fit the chart |
showObjects(labels, name?) |
Light and frame these seats, named in the legend. null clears |
The [focusSection] input opens the board on a section. The focusSection()
method frames a section later. In code, the input’s class field is
focusSectionOnOpen, because a class cannot have a field and a method with
the same name.
A method called before the board exists returns an empty answer.
getReport, getControlRoomSnapshot and setTrendWindow reject with
not ready.
Types
@seatlayer/angular/manager exports SeatManagerOpenOrder,
SeatManagerOpenTrend, SeatManagerOptions, SeatManagerMode,
EventScopedManageToken, SeatManagerTallies, SeatManagerSale,
SeatManagerActivity, SeatManagerActionResult, SeatManagerConnection,
SeatManagerRoomState, SeatManagerFilteredSection,
SeatManagerSelectionValidity, SeatManagerCategoryPrice,
EventTableBookingMode, ControlRoomActivityEntry,
ControlRoomSectionMetric and ControlRoomSnapshot.
Continue to the SeatManager reference, the control-room guide, and embed sessions.