rx-stomp with Angular
This step-by-step guide creates a new Angular application and demonstrates how to use rx-stomp.
While preparing this guide, Angular 13.2.0
and @stomp/rx-stomp 1.1.4
were used. The concepts apply to Angular 7+.
For the impatient, the final code from this tutorial is here: https://github.com/stomp-js/rx-stomp-angular
Prerequisites
- Install Node.js and npm.
- Basic familiarity with Angular and TypeScript. If unsure, start with Tour of Heroes.
Instructions
Create a new Angular application
Install the latest Angular CLI:
npm i @angular/cli -g
Scaffold the project:
ng new rx-stomp-angular --skip-install --defaults
cd rx-stomp-angular/
npm i
Run locally and open http://localhost:4200/:
ng serve
Keep this running. Angular CLI will rebuild and live-reload on changes.
Use your favorite IDE to edit code while the dev server runs.
Add @stomp/rx-stomp and inject RxStompService
Install the library:
npm i @stomp/rx-stomp
We’ll define configuration and wire it via Angular Dependency Injection when creating RxStompService
.
Configuration
Create src/app/my-rx-stomp.config.ts
:
import { RxStompConfig } from '@stomp/rx-stomp';
export const myRxStompConfig: RxStompConfig = {
// Which server?
brokerURL: 'ws://127.0.0.1:15674/ws',
// Headers (typical keys: login, passcode, host)
connectHeaders: {
login: 'guest',
passcode: 'guest',
},
// Heartbeats (ms). Set 0 to disable.
heartbeatIncoming: 0,
heartbeatOutgoing: 20000,
// Reconnect delay (ms). Set 0 to disable.
reconnectDelay: 200,
// Console diagnostics (avoid in production)
debug: (msg: string): void => {
console.log(new Date(), msg);
},
};
Works out-of-the-box with a default RabbitMQ STOMP-over-WebSocket setup; adjust for your broker.
The RxStompService
Create src/app/rx-stomp.service.ts
:
import { Injectable } from '@angular/core';
import { RxStomp } from '@stomp/rx-stomp';
@Injectable({
providedIn: 'root',
})
export class RxStompService extends RxStomp {
constructor() {
super();
}
}
Factory to create and initialize RxStompService
Create src/app/rx-stomp-service-factory.ts
:
import { RxStompService } from './rx-stomp.service';
import { myRxStompConfig } from './my-rx-stomp.config';
export function rxStompServiceFactory() {
const rxStomp = new RxStompService();
rxStomp.configure(myRxStompConfig);
rxStomp.activate();
return rxStomp;
}
Angular DI setup
In src/app/app.module.ts
, add a provider:
providers: [
{
provide: RxStompService,
useFactory: rxStompServiceFactory,
},
];
And import near the top:
import { RxStompService } from './rx-stomp.service';
import { rxStompServiceFactory } from './rx-stomp-service-factory';
Messages
We’ll build a component that:
- Sends a message on button click.
- Subscribes and lists received messages.
Skeleton
Create the Messages
component:
ng generate component messages
Set src/app/messages/messages.component.html
:
<div id="messages">
<button class="btn btn-primary">Send Test Message</button>
<h2>Received messages</h2>
<ol>
<!-- list will be populated via Angular binding -->
<li class="message">message</li>
</ol>
</div>
Add the component to the main UI (src/app/app.component.html
):
<div style="text-align:center">
<h1>Welcome to !</h1>
</div>
<app-messages></app-messages>
Check the browser to confirm the updated UI. If the page is blank, check terminal output from ng serve
and the browser console for errors.
Sending messages
Inject RxStompService
into MessagesComponent
(src/app/messages/messages.component.ts
):
constructor(private rxStompService: RxStompService) {}
Add a click handler:
onSendMessage() {
const message = `Message generated at ${new Date()}`;
this.rxStompService.publish({ destination: '/topic/demo', body: message });
}
See RxStomp#publish for options like headers, receipts, and binary payloads.
src/app/messages/messages.component.ts
(so far):
import { Component, OnInit } from '@angular/core';
import { RxStompService } from '../rx-stomp.service';
@Component({
selector: 'app-messages',
templateUrl: './messages.component.html',
styleUrls: ['./messages.component.css'],
})
export class MessagesComponent implements OnInit {
constructor(private rxStompService: RxStompService) {}
ngOnInit(): void {}
onSendMessage() {
const message = `Message generated at ${new Date()}`;
this.rxStompService.publish({ destination: '/topic/demo', body: message });
}
}
Wire the button in the template with (click)="onSendMessage()"
:
<div id="messages">
<button class="btn btn-primary" (click)="onSendMessage()">
Send Test Message
</button>
<h2>Received messages</h2>
<ol>
<!-- list will be populated via Angular binding -->
<li class="message">message</li>
</ol>
</div>
Open the browser console. Clicking “Send Test Message” should log frame activity from the debug logger.
Receiving messages
Use RxStomp#watch to subscribe to /topic/demo
:
ngOnInit() {
this.rxStompService.watch('/topic/demo').subscribe((message: Message) => {
this.receivedMessages.push(message.body);
});
}
Import Message
from @stomp/stompjs
and declare the array. Then bind the list with ngFor
.
A few other modules also expose Message
classes, so you need to be careful.
If you are coming from @stomp/stompjs
, please notice that you do not
need to subscribe within the callback of stomp getting connected.
This library internally ensures that actual subscription happens
when the broker is actually connected.
It also keeps track of broker re-connections and automatically resubscribes.
Update src/app/messages/messages.component.html
to render messages:
<li class="message" *ngFor="let message of receivedMessages"></li>
Complete files:
import { Component, OnInit } from '@angular/core';
import { RxStompService } from '../rx-stomp.service';
import { Message } from '@stomp/stompjs';
@Component({
selector: 'app-messages',
templateUrl: './messages.component.html',
styleUrls: ['./messages.component.css'],
})
export class MessagesComponent implements OnInit {
receivedMessages: string[] = [];
constructor(private rxStompService: RxStompService) {}
ngOnInit(): void {
this.rxStompService.watch('/topic/demo').subscribe((message: Message) => {
this.receivedMessages.push(message.body);
});
}
onSendMessage() {
const message = `Message generated at ${new Date()}`;
this.rxStompService.publish({ destination: '/topic/demo', body: message });
}
}
<div id="messages">
<button class="btn btn-primary" (click)="onSendMessage()">
Send Test Message
</button>
<h2>Received messages</h2>
<ol>
<li class="message" *ngFor="let message of receivedMessages">
</li>
</ol>
</div>
Try sending a few messages, then open another browser tab/window: both should receive messages.
Stopping the watch
Unsubscribe when the component is destroyed to avoid leaks:
- Implement
OnDestroy
. - Store the
Subscription
returned bysubscribe
. - Call
unsubscribe()
inngOnDestroy
.
import { Component, OnDestroy, OnInit } from '@angular/core';
import { RxStompService } from '../rx-stomp.service';
import { Message } from '@stomp/stompjs';
import { Subscription } from 'rxjs';
@Component({
selector: 'app-messages',
templateUrl: './messages.component.html',
styleUrls: ['./messages.component.css'],
})
export class MessagesComponent implements OnInit, OnDestroy {
receivedMessages: string[] = [];
private topicSubscription!: Subscription;
constructor(private rxStompService: RxStompService) {}
ngOnInit() {
this.topicSubscription = this.rxStompService
.watch('/topic/demo')
.subscribe((message: Message) => {
this.receivedMessages.push(message.body);
});
}
ngOnDestroy() {
this.topicSubscription.unsubscribe();
}
onSendMessage() {
const message = `Message generated at ${new Date()}`;
this.rxStompService.publish({ destination: '/topic/demo', body: message });
}
}
Tip: You can also use the RxJS takeUntil pattern with a Subject if you prefer that style.
Troubleshooting and tips
- Connection URL: Ensure
brokerURL
points to your broker’s STOMP-over-WebSocket endpoint (e.g., RabbitMQ default:ws://localhost:15674/ws
). - CORS/HTTPS: When serving the Angular app over HTTPS, use
wss://
and ensure certificates are valid. - Heartbeats: Some proxies or brokers may need heartbeats tuned; start with
incoming: 0
,outgoing: 20000
and adjust. - Debug logs: Keep
debug
enabled during development to see connection and frame flow. - Auth tokens: For token-based auth, see the token authentication FAQ and set headers in
connectHeaders
.
Where next
- Browse the sample code: https://github.com/stomp-js/rx-stomp-angular
- Explore RxStomp to discover more methods and options.
- Learn Angular Dependency Injection.
- Show connection status in the UI: Observing STOMP connection.
- Use token authentication with your broker.