Creating a Real Time Chat Application with Ionic 2 and Socket.io

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 2 because it is what Ionic 2 is built around.  Since the previous tutorial was Angular 2, we have an easier migration from web to mobile.

Here are some prerequisites that must be accounted for:

  • Couchbase Server 4+
  • Node Package Manager (NPM)
  • Ionic 2 and Apache Cordova
  • The Android SDK, iOS SDK, or both

Configure the Socket.io Server

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):

The Node.js code is valuable to us for this particular tutorial, not so much the Angular 2 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:

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:

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.

Build the Ionic 2 Mobile Application

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:

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:

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:

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:

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.

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 2 is out of beta, this may no longer be necessary.

Now let’s jump into the constructor method.

This is the host of the Node.js Socket.io server.  For me, it is running locally, but yours might not be.

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:

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.

Testing Communication Between the Socket.io Client and Server

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:

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:

Or for Android you can execute the following:

This of course needs to be run in a separate Terminal or Command Prompt that is within your Ionic 2 project.

Ionic 2 Web Chat iOS 1 Ionic 2 Web Chat iOS 2

Your application will look like the above.

Conclusion

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.

Nic Raboy

Nic is a skilled application developer who has released several native and hybrid mobile applications to iTunes and Google Play. He writes about his development experiences related to making web and mobile app development easier to understand and has experience in Android, Node.js, Apache Cordova, Java, NoSQL, SQL, GoLang, NativeScript, and Unity3D.

  • David Oddoye

    Another nice post. Thanks for your hard work

    • No problem, thanks for the compliment!

  • Phone Gapps

    Thanks for the article, I’ve been wanting to try SocketIO for some time already. Do you know on what versions of iOS and Android it works?
    I’ve seen http://socket.io/socket-io-with-apache-cordova/ but they don’t say anything about the versions (from the image I assume it at least works on iOS 7.1).

    • I can’t think of a reason why this would be device version specific. Should work for everything.

  • Kim Wong

    will not get the page transition animate when nav.pop() or nav.push().

    Have you have any sol?

    • I’m not sure what you’re asking

  • Spencer Bigum

    Hey Nic,
    Awesome post – your Ngzone helped me get through a big hurdle. Right now I have an ionic2 app + NG2 + firebase and im trying to get the data to sync live on the app. When the emulator is running – it syncs almost instant when I update the DB. When I have the app running on my actual phone – it takes about 30 sec for it to sync up….any ideas why it takes longer? Any ideas on how to speed it up? And lastly thank you so much for your post again!

    Cheers,
    S

  • Luchillo17

    Hey awesome work, i have a few questions, have you seen this video about RxJS? https://youtu.be/KOOT7BArVHQ?t=22m59s
    It basically states how to use RxJS with web sockets, they handle websocket closing due to connection loss, if you just let socket.io handle it, it will start polling, which will most likely drain battery life, however they close the websocket and wait for windown.online event (i know this doesn’t work in mobile hybrid app) to re-connect to the server, so i think it would be wise to add that to this along with the cordova plugin to check for network connection, what do you think?

    • I’ve not seen that video, but it would make sense that further optimization should be added to my example. My example is only basic and doesn’t handle everything.

      You probably do only want to enable socket.io when an internet connection is available. I don’t know too much on RxJS, but that might do the trick too.

      Thanks for sharing this video. It will be useful for people who want to take this tutorial to the next level 🙂

  • Paul Kitatta

    How can I contact you privately Nic

    • I don’t offer private help, sorry. You’ll have to use the comments, where relevant or Twitter.

      • Paul Kitatta

        But do you do some outsourcing jobs?

  • Chaiya Louer

    hello, Nic i would like ask u a question. my code work fine on pc browser but on mobile can’t connect to socket io server. page wast blank.

  • Alugbin Abiodun

    please what if i want to listen for messages on app.js but i want to emit from the chat page without creating a new socket instance, is there any way i can do that???

    • Can you explain your intentions?

      • Alugbin Abiodun

        i want to use only one instance of socket io within my ionic application. I created a this.socket in app.js where i listen for messages, and in another page, i created another this.socket which emits events. this end up creating a new connection to the server. but i want to create only one connection to listen and emit in all my ionic 2 pages.

        • Michael Olukoya

          Hey I had this problem recently, but realised a better way of doing it. Basically you need to make a service class. Initialise that service in your app.js (in ionic2) I did that using the second param in the bootstrap.

          Then simply import that service into all the components that need it, in your service make sure you setup a class property that that holds the socket instance. And simply refer to it in your individual component classes. That way you use one socket connection, rather than creating multiple when you open a new component.

          Nick’s tutorial shows the basics of how to integrate socket.io. But if you want to do it globally and keep it DRY, then make a service for it. And refer to this.socket which is in the service.

          tl:dr, don’t initialise socket.io in your components, initialise it in a service and just include it globally in your bootstrap

  • Guilherme Rodrigues

    Is this still working? i’ve just tried following the steps but had some erros like

    Error with start Error: No starter template named “start”

    • That was a typo. Should be “blank” instead. I’ll correct it.

  • Thomas Thai

    I made some changes and got this working with Ionic 2 RC2 and PostgreSQL. My server is on AWS and I was testing the Ionic 2 client on my laptop. I can send and receive messages. Again, just like the Angular web client from the previous tutorial, I don’t see old messages load at the initial point. In fact, this one gave me a different error:

    XMLHttpRequest cannot load api.MYSERVER.com:3000/fetch. Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource.

    Here is the constructor from home.ts:

    constructor(http: Http, public navCtrl: NavController) {

    • Thomas Thai

      Got both of those errors fixed. The issue was I forgot to add “http://” in front of the host name.

      socketHost = “api.MYSERVER.com:3000”;

      when I should of had:

      socketHost = “http://api.MYSERVER.com:3000”;

      export class HomePage {
      messages = [];
      socketHost = “http://api.MYSERVER.com:3000”;
      zone = new NgZone({enableLongStackTrace: false});
      chatBox = “”;
      socket = io(this.socketHost);

      I’m curious why “ionic serve”worked without the “http://” part.

    • Thomas Thai

      I now have the initial retrieval of previous messages showing up. The error was in:

      ChatModel:

      function getAll(req, res, next) {
      db.any(‘select * from messages ORDER BY message_date DESC LIMIT 20’)
      .then(function (data) {
      res.status(200).json(data); // <== used to read … json(data: data);
      })
      .catch(function (err) {
      console.log(“ERR:”, err.message || err);
      return next(err);
      });

      }

      Also I put a LIMIT to the number of rows retrieved as it would be too man to re-read for someone just joining. I also used DESC to retrieve the order in descending so I only get the last few messages. But that would mean the last message would be at the top of the display, then the next oldest right below that, so on… The array’s reverse() method fixed that.

      export class DefaultPage {

  • a n onymous

    I would love to see a socket.io and ionic 2 app that uses sockets for something more complicated than yet another chat app; e.g., streaming data for finance, health, server status, etc.

    • In theory, if you understand sockets in a chat application, you can do all of that yourself. So many chat applications exist because more people can relate to them versus these niche scenarios.