ng2-stompjs with Angular 7
This step by step guide will create a new Angular application and demonstrate usage of ng2-stompjs.
While preparing this guide Angular
7.0.4
and
@stomp/ng2-stompjs
7.0.0
are used.
For the impatient, final code from this tutorial is at: https://github.com/stomp-js/ng2-stompjs-angular7
Pre requisites
You need to have Node.js and npm installed.
You must have basic familiarity with Angular and Typescript. If you are unsure, please go through the famous Tour of Heroes.
Instructions
Create a new Angular Application
Install latest Angular CLI as below:
$ npm i @angular/cli -g
Change to the folder where you want to create the application and create your new application:
$ ng new ng2-stompjs-angular7 --skip-install --defaults
Change to new created folder and install all dependencies:
$ cd ng2-stompjs-angular7/
$ npm i
To run the application locally execute the following and point your browser to http://localhost:4200/.
$ ng serve
You can keep it running in a terminal and keep the browser tab open. It will detect changes, recompile and reload the browser tab.
At this stage you can use favorite IDE and be ready to edit code.
Add and Inject @stomp/ng2-stompjs
$ npm i @stomp/ng2-stompjs
We will need to define our configuration.
This configuration will get injected by Angular Dependency Injection mechanism
while creating instance of RxStompService
.
Create my-rx-stomp.config.ts
file inside src/app/
with the following content:
import { InjectableRxStompConfig } from '@stomp/ng2-stompjs';
export const myRxStompConfig: InjectableRxStompConfig = {
// Which server?
brokerURL: 'ws://127.0.0.1:15674/ws',
// Headers
// Typical keys: login, passcode, host
connectHeaders: {
login: 'guest',
passcode: 'guest',
},
// How often to heartbeat?
// Interval in milliseconds, set to 0 to disable
heartbeatIncoming: 0, // Typical value 0 - disabled
heartbeatOutgoing: 20000, // Typical value 20000 - every 20 seconds
// Wait in milliseconds before attempting auto reconnect
// Set to 0 to disable
// Typical value 500 (500 milli seconds)
reconnectDelay: 200,
// Will log diagnostics on console
// It can be quite verbose, not recommended in production
// Skip this key to stop logging to console
debug: (msg: string): void => {
console.log(new Date(), msg);
},
};
The above should work for a out of the box installation of RabbitMQ broker. Please change as per your broker configuration.
Next we need to configure the configuration to get injected. Open src/app/app.module.ts
Add the following to the providers
array of your @NgModule
:
providers: [
{
provide: InjectableRxStompConfig,
useValue: myRxStompConfig,
},
{
provide: RxStompService,
useFactory: rxStompServiceFactory,
deps: [InjectableRxStompConfig],
},
];
Also add appropriate import lines towards the top of this file (after existing import statements):
import {
InjectableRxStompConfig,
RxStompService,
rxStompServiceFactory,
} from '@stomp/ng2-stompjs';
import { myRxStompConfig } from './my-rx-stomp.config';
Messages
We will create a component that will do the following:
- It will have a click-able button to send a message.
- It will subscribe and keep listing all received messages.
Skeleton
Create the Messages
component:
$ ng generate component messages
Inspect the files generated in src/app/messages/
.
Now we will create the basic HTML in
src/app/messages/messages.component.html
- put the following content:
<div id="messages">
<button class="btn btn-primary">Send Test Message</button>
<h2>Received messages</h2>
<ol>
<!-- we will use Angular binding to populate list of messages -->
<li class="message">message</li>
</ol>
</div>
We will add this component to the main UI by editing src/app/app.component.html
.
In this process we will remove most of the default HTML generated by Angular CLI.
Edit src/app/app.component.html
to look like the following:
<div style="text-align:center">
<h1>Welcome to !</h1>
</div>
<app-messages></app-messages>
This is a great time to check the browser tab to see that display has changed
and it should show the HTML that we have added to src/app/messages/messages.component.html
.
If you find an empty screen, please check the terminal where you executed ng serve
, if
there are compilation errors you would see it here. Also, see the browser Javascript
console, sometimes you may notice errors here.
Sending messages
We will now inject RxStompService
as a dependency in MessageComponent
.
To that we will add it to the constructor in src/app/messages/messages.component.ts
,
which should look like the following:
constructor(private rxStompService: RxStompService) { }
We will now add code to send message:
onSendMessage() {
const message = `Message generated at ${new Date}`;
this.rxStompService.publish({destination: '/topic/demo', body: message});
}
Please see RxStomp#publish. Keep this page open as we would be using more methods from this class soon.
Full content of src/app/messages/messages.component.ts
should look like
the following:
import { Component, OnInit } from '@angular/core';
import { RxStompService } from '@stomp/ng2-stompjs';
@Component({
selector: 'app-messages',
templateUrl: './messages.component.html',
styleUrls: ['./messages.component.css'],
})
export class MessagesComponent implements OnInit {
constructor(private rxStompService: RxStompService) {}
ngOnInit() {}
onSendMessage() {
const message = `Message generated at ${new Date()}`;
this.rxStompService.publish({ destination: '/topic/demo', body: message });
}
}
We will attach onSendMessage
to the button in the html.
Edit src/app/messages/messages.component.html
and add (click)="onSendMessage()"
to the button. The file should look like the following now:
<div id="messages">
<button class="btn btn-primary" (click)="onSendMessage()">
Send Message
</button>
<h2>Received messages</h2>
<ol>
<!-- we will use Angular binding to populate list of messages -->
<li class="message">message</li>
</ol>
</div>
At this stage you should go back to the browser tab and open the web console.
When you click on the Send Message
button, you can see in the console that message
is being sent to the broker.
Receiving messages
The RxStomp#watch method
initiates a subscription with the broker. =
this.rxStompService.watch('/topic/demo')
will initiate a subscription
with the broker for topic /topic/demo
and returns an RxJS Observable
.
Typically we will subscribe this Observable
to receive actual messages.
ngOnInit() {
this.rxStompService.watch('/topic/demo').subscribe((message: Message) => {
this.receivedMessages.push(message.body);
});
}
We will need to add a declaration for receivedMessages
and import Message
from @stomp/stompjs
.
There are Message
classes exposed by few other modules as well, so,
you need to be careful.
If you are coming from @stomp/stompjs
, please notice that you do not
need to subscribe within callback of stomp getting connected.
This library internally ensures that actual subscription is carried out
when the broker is actually connected.
It also keep tracking of broker re-connections and automatically resubscribes.
Now is the time to link the HTML template to received messages.
We will use ngFor
to bind list of messages to <li>
.
Edit src/app/messages/messages.component.html
:
<li class="message" *ngFor="let message of receivedMessages"></li>
Now your src/app/messages/messages.component.ts
and
src/app/messages/messages.component.html
should look like:
import { Component, OnInit } from '@angular/core';
import { RxStompService } from '@stomp/ng2-stompjs';
import { Message } from '@stomp/stompjs';
@Component({
selector: 'app-messages',
templateUrl: './messages.component.html',
styleUrls: ['./messages.component.css'],
})
export class MessagesComponent implements OnInit {
public receivedMessages: string[] = [];
constructor(private rxStompService: RxStompService) {}
ngOnInit() {
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 Message
</button>
<h2>Received messages</h2>
<ol>
<!-- we will use Angular binding to populate list of messages -->
<li class="message" *ngFor="let message of receivedMessages">
</li>
</ol>
</div>
Check your application in the browser now. Try sending few messages. Open another browser window/tab and see messages being received in both.
Stopping the watch
We are almost done, we just need to add stopping the watch when the component is destroyed.
For this we need to call unsubscribe
on the RxJS subscription when we are done.
MessagesComponent
will need to implement OnDestroy
. For this we will need to do
the following:
- Add
OnDestroy
to the implements list (by defaultOnInit
will be there). - Implement
ngOnDestroy
method. - Add
OnDestroy
to the imports.
Once the above is done we will modify code in ngOnInit
to store the RxJS
subscription in a member variable and call unsusbscribe
in ngOnDestroy
.
ngOnInit() {
this.topicSubscription = this.rxStompService.watch('/topic/demo').subscribe((message: Message) => {
this.receivedMessages.push(message.body);
});
}
ngOnDestroy() {
this.topicSubscription.unsubscribe();
}
Type of topicSubscription
will be Subscription
from rxjs
.
Your src/app/messages/messages.component.ts
should look like the following:
import { Component, OnDestroy, OnInit } from '@angular/core';
import { RxStompService } from '@stomp/ng2-stompjs';
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 {
public 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 });
}
}
Where next
- Browse the code at https://github.com/stomp-js/ng2-stompjs-angular7
- Explore RxStomp to understand other interesting methods exposed by the library.
- Go through Angular Dependency Injection - trust me mastering it will take you places.
- Observing STOMP connection status and showing a visual indicator.
- Using token authentication with the STOMP broker.
I will be writing more tutorials in following days to cover additional topics:
- Manual control in the configuration and connection establishment. (In this sample, STOMP broker is connected during the Angular DI class initialization phase.)