Have you ever wanted to build a mobile real-time chat application? Previously I demonstrated how to build a real-time chat application using the CEAN web stack using Socket.io. This is essentially part two to that tutorial.
We’re going to take a look at what it takes to create a chat application using Socket.io and the mobile web framework Ionic 2.
If you haven’t already, I strongly encourage you to read the previous tutorial as we’re going to be recycling many of the code and concepts. For example we’re going to be using Angular because it is what Ionic 2 is built around. Since the previous tutorial was Angular, we have an easier migration from web to mobile.
Here are some prerequisites that must be accounted for:
To make our lives easy, we’re going to clone the project I created previously from GitHub. Download this project or execute the following from a Terminal (Mac and Linux) or Command Prompt (Windows):
git clone https://github.com/couchbaselabs/cean-web-chat
The Node.js code is valuable to us for this particular tutorial, not so much the Angular TypeScript code.
Don’t forget to install all the Node.js dependencies after you download the project. They can be installed by executing the following:
npm install
We also need to make one change to the Node.js code. Since I’m going to be running everything from my local computer we’re going to have a few different ports in use. This will create cross origin resource sharing (CORS) issues that we need to correct. In the GitHub project, open the app.js file and add the following above the routes section:
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
Now CORS is accepted in our Node.js locally running server.
You will need Couchbase Server for this application because the Node.js project from GitHub uses it. Instructions for configuring can be found in the previous tutorial.
We’re now going to create a fresh Ionic 2 Android and iOS project. From the Command Prompt (Windows) or Terminal (Mac and Linux), execute the following:
ionic start ionic-web-chat blank --v2
cd ionic-web-chat
ionic platform add ios
ionic platform add android
A few important things to note here. You need to be using the Ionic CLI that supports Ionic 2 applications. You must also be using a Mac if you wish to add and build for the iOS platform.
We’re going to spend most of our time in two particular Ionic project files, however, we first need to download the Socket.io client library and include it in our project. Download the latest client release. I’m using version 1.2.0. Copy the socket.io-1.2.0.js file downloaded to your Ionic project’s www/js directory. Next open the www/index.html file and include this line:
<script src="js/socket.io-1.2.0.js"></script>
It needs to be added before the other scripts. Now we can get to the bulk of our development.
Starting with the UI file, open app/pages/home/home.html and change the code to look like the following:
<ion-navbar *navbar>
<ion-title>
Home
</ion-title>
</ion-navbar>
<ion-content class="home">
<ion-list>
<ion-item *ngFor="#message of messages">{{message}}</ion-item>
</ion-list>
</ion-content>
<ion-footer-bar>
<ion-input>
<input type="text" [(ngModel)]="chatBox" placeholder="Message..." />
<button (click)="send(chatBox)">Send</button>
</ion-input>
</ion-footer-bar>
There is a lot missing as of right now, but here is the breakdown starting from the bottom.
We add an <ion-footer-bar>
because it is the easiest way to create a sticky footer in Ionic Framework. We need a sticky footer because we want our chat input box and send button to always remain at the bottom. The input
field is tied to the chatBox
model which is passed when the button
calls the send()
function. Both the send()
function and chatBox
model will be seen again in the logic file.
Moving up to our <ion-list>
we can see we’re looping through a messages
array. Each message will represent something received from Socket.io. It too will be defined in our logic file.
Now let’s jump into our logic file. Open your project’s app/pages/home/home.js file and change the code to look like the following:
import {Page} from 'ionic/ionic';
import {Http} from "angular2/http";
import {NgZone} from "angular2/core";
@Page({
templateUrl: 'build/pages/home/home.html',
})
export class HomePage {
constructor(http: Http) {
this.messages = [];
this.socketHost = "http://192.168.57.1:3000";
this.zone = new NgZone({enableLongStackTrace: false});
http.get(this.socketHost + "/fetch").subscribe((success) => {
var data = success.json();
for(var i = 0; i < data.length; i++) {
this.messages.push(data[i].message);
}
}, (error) => {
console.log(JSON.stringify(error));
});
this.chatBox = "";
this.socket = io(this.socketHost);
this.socket.on("chat_message", (msg) => {
this.zone.run(() => {
this.messages.push(msg);
});
});
}
send(message) {
if(message && message != "") {
this.socket.emit("chat_message", message);
}
this.chatBox = "";
}
}
There is a lot going on in the above, but if you read my Socket.io with the CEAN stack tutorial, not much of it is new. Let’s break it down anyways though.
import {Http} from "angular2/http";
import {NgZone} from "angular2/core";
Like with the previous tutorial, we’re going to be storing our chat history in a Couchbase Server. Our Node.js application has a single endpoint for fetching all chat messages. This endpoint is consumed over HTTP. The NgZone
was included because it helps with checking for changes. When Angular is out of beta, this may no longer be necessary.
Now let’s jump into the constructor
method.
this.socketHost = "http://192.168.57.1:3000";
This is the host of the Node.js Socket.io server. For me, it is running locally, but yours might not be.
http.get(this.socketHost + "/fetch").subscribe((success) => {
var data = success.json();
for(var i = 0; i < data.length; i++) {
this.messages.push(data[i].message);
}
}, (error) => {
console.log(JSON.stringify(error));
});
When the page loads, we immediately consume the fetch endpoint to catch us up with the rest of the group. We wouldn’t want to join and miss out on all the conversations.
This is where things become slightly different than the CEAN tutorial:
this.socket = io(this.socketHost);
this.socket.on("chat_message", (msg) => {
this.zone.run(() => {
this.messages.push(msg);
});
});
When messages are received we push them into the array from within the this.zone.run
method. Currently, without this, the messages may not update on the screen.
Now let’s see this chat application in action.
First we want to start the Node.js and Socket.io server. Using your Command Prompt or Terminal, from within the GitHub project, execute the following:
node app.js
Remember your Couchbase installation must be running and configured as seen in the previous tutorial, otherwise running may fail.
With the server running, you can now build and run for one of the mobile platforms.
For iOS you can do the following, provided you’re on a Mac:
ionic emulate ios
Or for Android you can execute the following:
ionic run android
This of course needs to be run in a separate Terminal or Command Prompt that is within your Ionic 2 project.
Your application will look like the above.
We just took our real-time chat application to the next level by allowing a mobile version of it to join in on the fun. Previously we used the Couchbase, Express, Angular, and Node.js (CEAN) stack to create a chat application and this time around we added a mobile version that can not only communicate to other mobile apps, but the web version as well.
This project can be downloaded in full on GitHub.