Inter-component messaging system for dashboard applications using a transmitter-receiver pattern.
The notification system allows dashboard components to communicate without direct coupling:
Location: Framework/COMMON/WEBSITE/Intf.Supports.Messages.pas
TMessageType enum defines all message categories:
| Type | Description |
|---|---|
mtChartButtonClick | Switch to chart view |
mtMapButtonClick | Switch to map view |
mtCardShowGrid | Show raw data grid |
mtLegend | Toggle legend visibility |
mtCardDelete | Delete card request |
| Type | Description |
|---|---|
mtCanvasMaximize | Maximize card to full canvas |
mtCanvasMinimize | Restore card from maximized |
mtCanvasExpandRight | Expand card width by 1 column |
mtCanvasExpandDown | Expand card height by 1 row |
mtCanvasShrinkLeft | Shrink card width by 1 column |
mtAdjustLayout | Recalculate grid layout |
| Type | Description |
|---|---|
mtRefreshData | Reload card data from server |
mtDateRangeChanged | Date filter changed |
mtFilterChanged | General filter changed |
TYPE
IMessageTransmitter = INTERFACE
['{GUID}']
PROCEDURE TransmitMessage(MessageType: TMessageType;
Payload: TCardPayload = NIL);
PROCEDURE ConnectReceiver(Receiver: IMessageReceiver);
PROCEDURE DisconnectReceiver(Receiver: IMessageReceiver);
END;
TYPE
TMessageTransmitter = CLASS(TInterfacedObject, IMessageTransmitter)
PRIVATE
FReceivers: TList<IMessageReceiver>;
PUBLIC
PROCEDURE TransmitMessage(MessageType: TMessageType;
Payload: TCardPayload = NIL);
BEGIN
FOR Receiver IN FReceivers DO
Receiver.HandleMessage(MessageType, Payload);
END;
END;
TYPE
IMessageReceiver = INTERFACE
['{GUID}']
PROCEDURE HandleMessage(MessageType: TMessageType;
Payload: TCardPayload);
END;
TYPE
TDashboardCanvas = CLASS(TCoreDiv, IMessageReceiver)
PRIVATE
PROCEDURE HandleMessage(MessageType: TMessageType;
Payload: TCardPayload);
END;
PROCEDURE TDashboardCanvas.HandleMessage(MessageType: TMessageType;
Payload: TCardPayload);
BEGIN
CASE MessageType OF
mtCanvasMaximize:
MaximizeCard(Payload.CardID);
mtCanvasMinimize:
RestoreCard(Payload.CardID);
mtCardDelete:
DeleteCard(Payload.CardID);
mtAdjustLayout:
RecalculateLayout;
END;
END;
TYPE
TCardPayload = CLASS
PUBLIC
CardID: Integer; /// Affected card ID
SourceComponent: TObject; /// Sender reference
Data: TJSObject; /// Optional JSON data
StringValue: STRING; /// Optional string data
IntValue: Integer; /// Optional integer data
CONSTRUCTOR Create(ACardID: Integer);
END;
VAR
Payload: TCardPayload;
BEGIN
Payload := TCardPayload.Create(Card.CardID);
Payload.SourceComponent := Self;
Payload.StringValue := 'additional info';
Transmitter.TransmitMessage(mtCardDelete, Payload);
END;
/// In THeaderButton (transmitter)
PROCEDURE THeaderButton.DoOnClick;
VAR
Payload: TCardPayload;
BEGIN
Payload := TCardPayload.Create(OwnerCard.CardID);
Payload.SourceComponent := Self;
CASE Action OF
mtCanvasMaximize:
FTransmitter.TransmitMessage(mtCanvasMaximize, Payload);
mtCardShowGrid:
FTransmitter.TransmitMessage(mtCardShowGrid, Payload);
END;
END;
/// When card is created
PROCEDURE TDashboardCanvas.AddCard(Card: TDashboardCard);
BEGIN
/// Connect card's transmitter to canvas receiver
Card.Transmitter.ConnectReceiver(Self);
FCards.Add(Card);
END;
/// When card is removed
PROCEDURE TDashboardCanvas.RemoveCard(Card: TDashboardCard);
BEGIN
Card.Transmitter.DisconnectReceiver(Self);
FCards.Remove(Card);
END;
/// Sidebar filter change broadcasts to all cards
PROCEDURE TSidebar.OnDateRangeChange(NewStart, NewEnd: TDateTime);
VAR
Payload: TCardPayload;
BEGIN
Payload := TCardPayload.Create(0); /// 0 = all cards
Payload.Data := TJSObject.new;
Payload.Data['startDate'] := DateToISO(NewStart);
Payload.Data['endDate'] := DateToISO(NewEnd);
FTransmitter.TransmitMessage(mtDateRangeChanged, Payload);
END;