-
message-bus is just a small angular library which provides a singleton shared service in Angular application.
-
message-bus is just an improved shared service. Instead of providing just one instance for publishing | subscribing messages, it provides
channels
andevents
to which components can subscribe and unsubscribe. -
Long story short, message-bus provides
back-end
mindset about pub/sub mechanism. -
Online DEMO can be found HERE
1. Module lifetime
import {MessageBusModule} from './message-bus.module';
@NgModule({
declarations: [],
imports: [
//... Module declaration
MessageBusModule.forRoot()
],
providers: [
AppSettings
],
bootstrap: [AppComponent]
})
export class AppModule {
}
import {ChangeDetection} from '@angular/cli/lib/config/workspace-schema';
@Component({
// tslint:disable-next-line:component-selector
selector: 'parent',
templateUrl: 'parent.component.html',
changeDetection: ChangeDetection.OnPush
})
export class ParentComponent implements OnInit {
public constructor(@Inject(MESSAGE_BUS_SERVICE) public messageBusService: IMessageBusService) {
}
}
2. Component lifetime
@Component({
// tslint:disable-next-line:component-selector
selector: 'parent, [parent-comp]',
templateUrl: 'parent.component.html',
providers: [
{
provide: MESSAGE_BUS_SERVICE,
useFactory: () => new MessageBusService()
}
]
})
export class ParentComponent implements OnInit {
}
- Instead of defining channel name and event name manually each time when message is added to message channel or message channel is subscribed to. A class which inherits TypedChannelEvent class which helps developer not to declare channel name or event name repeatedly and exhaustedly.
- An example of class which inherits TypedChannelEvent class.
export class ModuleLevelMessageEvent extends TypedChannelEvent<string> {
//#region Properties
public readonly channelName: string;
public readonly eventName: string;
//#endregion
//#region Constructor
constructor() {
super();
this.channelName = MessageChannelNameConstant.parent;
this.eventName = MessageEventNameConstant.sendParentMessage;
}
//#endregion
}
-
To subscribe to an
event in message channel
, please usehookMessageChannelhookTypedMessageChannel. -
hookMessageChannel allows user to specify whether event and channel should be automatically created if they don't exist or not. -
hookMessageChannelhookTypedMessageChannel returns an instance ofSubscription
. Don't forget to unsubscribe it to prevent memory leak.
// ... Above implementation
//#region Constructor
public constructor(@Inject(MESSAGE_BUS_SERVICE) protected messageBusService: IMessageBusService) {
// Initialize subscription manager.
this._subscription = new Subscription();
const channelEvent = new ModuleLevelMessageEvent();
const hookParentTypedMessageSubscription = this.messageBusService
.hookTypedMessageChannel(channelEvent)
.subscribe((value: string) => {
this._typedMessage = value;
});
this._subscription.add(hookParentTypedMessageSubscription);
}
//#endregion
//#region Methods
public ngOnDestroy(): void {
// Destroy the subscription to prevent memory leak.
if (this._subscription && !this._subscription.closed) {
this._subscription.unsubscribe();
}
}
//#endregion
- To publish a message through message bus to a specific event in a channel, please use
addMessage. - The event and channel will be created automatically if they don't exist.
export class ComponentLevelParentComponent extends ParentComponent {
//#region Properties
//#endregion
//#region Constructor
public constructor(@Inject(MESSAGE_BUS_SERVICE) protected messageBusService: IMessageBusService) {
super();
}
//#endregion
//#region Methods
public clickSendTypedMessage(): void {
const channelEvent = new ModuleLevelMessageEvent();
const date = new Date();
const message = `${date.toLocaleTimeString()} [${this.name}] says: Hello`;
this.messageBusService
.addTypedMessage(channelEvent, message);
}
//#endregion
}
-
addMessageChannel(channelName: string, eventName: string): Subject : Create a channel and event in the message bus. (One channel has many events, however, one event can only belong to one channel.)channelName (string): Name of channel should the event and message be created. (required).eventName (string): Name of event in the channel above which message will go through. (required).
-
hookMessageChannel(channelName: string, eventName: string): Observable**: Subscribe to a specific channel and its event to listen to the incoming message. Every component which registers to the same channel and event can catch the message.channelName (string): Name of channel to subscribe to. (required).eventName (string): Name of event to subscribe to. (required).
-
addMessage(channelName: string, eventName: string, data?: T, lifeTimeInSeconds?: number): void: Publish a message to a specific event in a specific channel. Event component registers to the published channel and event can receive the sent message.channelName (string): Name of channel that message will be published to. (required).eventName (string): Name of event that message will go through. (required).data (any): Message data.lifeTimeInSeconds (options): The number of seconds message remains. If this parameter isn't set, message will have infinitive lifetime.
-
channelAddedEvent: Observable<{channelName: string, eventName: string}>: Raised when a channel is created successfully. This event can be used for initializing connection from subscriber to message bus to ensure the specific channel & event is available to be consumed. -
hookChannelInitialization(channelName: string, eventName: string): Observable: Provide hook to outer component to know when amessage channel - event
is initialized successfully.channelName (string): Name of channel.eventName (string): Name of event.
-
addTypedMessageChannel(channelEvent: TypedChannelEvent): void : Create a channel and event in the message bus. (One channel has many events, however, one event can only belong to one channel.)
- channelEvent (TypedChannelEvent): Combination of channel name & event name. This instance is for preventing developer from specifying channel name & event name & especially message data type manually. (required).
-
hookTypedMessageChannel(channelEvent: TypedChannelEvent): Observable: Subscribe to a specific channel and its event to listen to the incoming message. Every component which registers to the same channel and event can catch the message.
- channelEvent (TypedChannelEvent): Combination of channel name & event name. This instance is for preventing developer from specifying channel name & event name & especially message data type manually. (required).
-
addTypedMessage(channelEvent: TypedChannelEvent, message: T, lifeTimeInSeconds?: number): void: Publish a message to a specific event in a specific channel. Event component registers to the published channel and event can receive the sent message.
- channelEvent (TypedChannelEvent): Combination of channel name & event name. This instance is for preventing developer from specifying channel name & event name & especially message data type manually. (required).
- message (any): Message data.
- lifeTimeInSeconds (options): The number of seconds message remains. If this parameter isn't set, message will have infinitive lifetime.
-
channelAddedEvent: Observable<{channelName: string, eventName: string}>`: Raised when a channel is created successfully. This event can be used for initializing connection from subscriber to message bus to ensure the specific channel & event is available to be consumed.
-
hookTypedChannelInitialization(channelEvent: TypedChannelEvent): Observable;: Provide hook to outer component to know when a
message channel - event
is initialized successfully.- channelEvent (TypedChannelEvent): Combination of channel name & event name. This instance is for preventing developer from specifying channel name & event name & especially message data type manually. (required).
-
Module lifetime is about single instance in the whole module that
message bus
is registered. -
Component lifetime is about single instance in the component that
message bus
is registered. -
message bus
lifetime can be overridden by the innermessage bus
. That means, if there are 2 instances, one is registered in module, the other is in component, the component's one will be the active and runnable one. Please refer Hierarchical Dependency Injectors for more information.
-
13..:
-
3.0.1:
- Minor bug fix about injection token.
-
3.0.0:
-
Add typed channel event apis, such as:
-
addTypedMessageChannel
. -
hookTypedMessageChannel
. -
addTypedMessage
. -
hookTypedChannelInitialization
.
-
-
Marked weak typed methods as deprecated. Marked apis:
-
addMessageChannel
. -
hookMessageChannel
. -
addMessage
. -
hookChannelInitialization
.
-
-
-
2.2.0:
-
Removed
channelAddedEvent
. WhenhookChannelMessage
, it will ensure a channel is created before publishing messages. -
Added
lifetimeInSeconds?: number
intoaddMessage<T>(channelName: string, eventName: string, data: T, lifetimeInSeconds?: number): void
, message will be expired after lifetime exceeds. -
Removed
messageBusOptions
andforRoot
from module declaration. From now, module will be imported as default:
@NgModule({ imports: [ MessageBusModule, //... ] }) export class ModuleLevelDemoModule { }
- Removed
autoCreateChannel
fromhookChannelMessage
. - Changed
IMessageBusService
string injector toMESSAGE_BUS_SERVICE
object injector.
-
-
1.0.4:
- Changed
BehaviourSubject
toReplaySubject
to prevent unexpected value from being emitted.
- Changed
-
1.0.3: Minor bug fixes.
-
1.0.2: Minor bug fixes.
-
1.0.1: Added README.MD.
-
1.0.0: Initial release.