Making Angular.js realtime with Websockets

Learn how to use Pusher to enable a rich, real-time user experience with Angular.js, code samples and a demo.

Introduction

Update: We released an official Angular.js library since that blog post. You can read more about it in this announcement.

Looking for Angular 2? We’ve recently written a new blog post on Pusher and Angular 2 that will help you get started. This blog post focuses on Angular 1.

Front-end application frameworks have given developers the tools to build client side applications with rich user experiences. Let’s say your application is built with one of these frameworks and you want to notify connected clients that something on the server has changed – how can you do that while keeping a rich user experience? This is where Pusher and angular-pusher come into play.

Angular.js

Angular.js is a client side JavaScript framework built by Google. It provides the framework for building either small components that can be plugged into your website or entire single page applications. At the core of Angular.js is a module system that allows creating providers, services, factories, and directives.

All of these are used within controllers to create, retrieve, update, and delete data while providing nice features for manipulating the HTML DOM with little custom JavaScript code. This post won’t focus on the specifics of Angular.js, so some prior knowledge of creating and structuring an Angular.js application is recommended.

In a simple Angular.js application, data is retrieved and sent to and from a backend server through an $http or $resource service provided by the framework. Below is an example of retrieving a list of items from an API and updating the selected item using the $http service.

1var ItemListController = function ($scope, $http) {
2  // initialize a list of items on the scope
3  $scope.items = [];
4
5  var retrieveItems = function () {
6  // get a list of items from the api located at '/api/items'
7  $http.get('/api/items')
8    .success(function (items) {
9      $scope.items = items;
10    });
11  };
12
13  $scope.updateItem = function (item) {
14    $http.post('/api/items', item);
15  };
16
17  // load the items
18  retrieveItems();
19};
1<div>
2  <table>
3    <tbody>
4      <tr>
5        <th>Name</th>
6        <th>Qty</th>
7        <th></th>
8      </tr>
9      <tr>
10        <td><input type="text" /></td>
11        <td><input type="text" /></td>
12        <td><button type="button">Update</button></td>
13      </tr>
14    </tbody>
15  </table>
16</div>

If we needed to know when items have been updated on the server by another user, we would have to constantly poll the server to find out if the items array changed.

1var ItemListController = function ($scope, $http, $timeout) {
2
3  $scope.items = [];
4
5  var retrieveItems = function () {
6    // get a list of items from the api located at '/api/items'
7    $http.get('/api/items')
8      .success(function (items) {
9        $scope.items = items;
10
11        // check for item changes
12        $timeout(retrieveItems, 5000);
13      }
14    );
15  };
16
17...
18};

As you can see, we just update the items array every five seconds which isn’t something that we want to keep doing. If a user is making a lot of changes, then we don’t want to keep overwriting the items array. You could build the logic to only update changed items, but you still have the issue of polling the server every five seconds. It would be much nicer if we could subscribe to an event and wait for a notification of changes in real-time.

Making Angular.js real-time with Pusher

Using Pusher will allow us to subscribe to events triggered by other clients. First I’ll show you the simple changes needed in our ItemListController to use angular-pusher. Then I’ll show you an example of using Pusher in a Node.js server when an item is updated.

First, we need tell our Angular.js application to use angular-pusher. You can do this by either downloading the development or production files from GitHub or using bower install angular-pusher and loading them into your page with the following script tag:

1<script src="bower_components/angular-pusher/angular-pusher.min.js" type="text/javascript"></script>

This should be loaded after the angular.min.js file and before your application.js script.

Now we can tell our application that we want to use the services provided in angular-pusher.min.js.

1angular.module('myApp', ['doowb.angular-pusher']).
2
3config(['PusherServiceProvider',
4  function(PusherServiceProvider) {
5    PusherServiceProvider
6    .setToken('your_app_key')
7    .setOptions({});
8  }
9]);

The angular-pusher module has a PusherServiceProvider that can be configured when creating your application. Here is where you can set your Pusher application key (PusherServiceProvider.setToken('token')), additional Pusher options (PusherServiceProvider.setOptions(options)), and a specific version of Pusher (PusherServiceProvider.setPusherUrl(url)). The Pusher url has a default, but it may be an older version.

Now we can use Pusher in our controller to subscribe to events and be notified when our items array changes:

1var ItemListController = function($scope, $http, Pusher) {
2  $scope.items = [];
3
4  Pusher.subscribe('items', 'updated', function (item) {
5    // an item was updated. find it in our list and update it.
6    for (var i = 0; i < $scope.items.length; i++) {
7      if ($scope.items[i].id === item.id) {
8        $scope.items[i] = item;
9        break;
10      }
11    }
12  });
13
14  var retrieveItems = function () {
15  // get a list of items from the api located at '/api/items'
16  console.log('getting items');
17  $http.get('/api/items')
18    .success(function (items) {
19      $scope.items = items;
20    }
21  );
22};
23
24$scope.updateItem = function (item) {
25  console.log('updating item');
26  $http.post('/api/items', item);
27};
28
29// load the items
30retrieveItems();
31}

The following is an example of using Pusher with Express.js running on Node.js. Pusher isn’t restricted to just Node.js applications: there are many server libraries available to make it simple to connect to Pusher. In the Node.js server, we setup our connection to Pusher with a few lines of code and it only takes one more line of code to trigger the actual update notification:

1// setup Pusher
2var Pusher = require('pusher');
3var pusher = new Pusher({
4  appId: '12345',
5  key: 'some key',
6  secret: 'my secret... shhh!!!'
7});
8
9// in our express server
10// setup a post route and trigger the change in Pusher
11app.post('/api/items', function (req, res) {
12
13  // get our item from the req and update the item collection
14  // in a production application this would have validation and items
15  // would be stored in a database.
16  var item = req.body;
17  items[item.id] = item;
18
19  // tell Pusher to trigger an 'updated' event on the 'items' channel
20  // add pass the changed item to the event
21  pusher.trigger('items', 'updated', item);
22
23  // respond with the changed item
24  res.json(item);
25});

Get Pushing

All of this code can be found here on GitHub and the gh-pages branch contains the examples that these code snippets came from. The application itself can be found here. Open it now in 2 tabs or windows and witness the power of real-time yourself!

Hopefully this article and the code samples are enough to get your Angular.js application working with Pusher. If you have any questions, our support team is always there to help either via Twitter or via your own support panel.

For more tutorials to build realtime apps, check out our