Hopefully you have already worked with the exciting state management system for Angular 2+ NGXS. I found that there isn’t a lot of content online about NGXS +WebSocket + Laravel. So here I am, I would like to share how to add WebSocket integration for your Angular App if you are using Laravel as backend.
Let’s get started with a simple scheme, which explains how it works in general:
Let’s go deep into details:
- Client app establishes WebSocket connection to our NodeJs/Express server with channelName and clientID (random unique string):
connectToSocket() {const currentUser = JSON.parse(localStorage.getItem('currentUser'));const clientId = uuid.v4();this.store.dispatch(new SetClientID(clientId));if (currentUser && currentUser.token) {this.store.dispatch(new ConnectWebSocket({url: `${environment.nodeServerIp}?channelName=private-budget-${this.id}&token=${currentUser.token}&email=${currentUser.username}&clientId=${clientId}`,}),);}}
2. The client sends typical REST requests to Laravel with clientID and channelName in a payload.
3. Laravel extracts clientId and channelName and fires the Event class, which sends a message to Redis channel
event(new UpdateBudgetEvent($clientId, $budgetId, $budgets));**** UpdateBudgetEvent class ****class UpdateBudgetEvent extends Event implements ShouldBroadcast
{....
// broadcastOn method will send to Redis all PUBLIC propertiespublic function broadcastOn()
{
$data['type'] = '[App] SocketUpdateBudget';
$data['data'] = $this->budget;
$this->data = json_encode($data);
return new PrivateChannel('budget-' . $this->budgetId);
}
4. Nodejs application listens to Redis channel and when a message comes, NodeJs sends a message to the relevant client in the right channel
redis.on('pmessage', (pattern, channel, message) => {message = JSON.parse(message);wss.clients.forEach((client) => {// Check channelif (client.channelName == channel) {// Check clientif (client.clientId != message.data.clientId) {client.send(message.data.data);}}
5. NGXS will automatically get this message (from WebSocket frame) and dispatch the action which will adjust your state
// app.actions.ts
export class SocketUpdateBudget {static readonly type = '[App] SocketUpdateBudget';constructor(public data: any[]) {}}// app.state.ts
@Action(SocketUpdateBudget)socketUpdateBudget(ctx: StateContext<AppStateModel>,data: SocketUpdateBudget,) {const state = ctx.getState();// DO your logic with state here}
And that’s actually it, pretty straightforward. Hope it any Angular/NGXS developers out there.
Final result:
If you want to see more you can also play around at myracle.co.
Hope it was useful reading, don’t hesitate if you have questions or comments and don’t forget to 👏 if this article saves some time in your coding path…