Example of realtime AngularJS app using HTML5 server-sent events.
Page Contents

Angular Live Set: Example

What is LiveSet?

LiveSet is an angular module that allows you to display an always up to date collection of objects.

gif

Lets see the code!

Favorite Colors

This is a snippet from the colors example that demonstrates a basic LiveSet.

var src = new EventSource('/api/colors/change-stream');
var changes = createChangeStream(src);
var set;

Color.find().$promise.then(function(results) {
  set = new LiveSet(results, changes);
  $scope.colors = set.toLiveArray();
});

Live Drawing

The drawing example creates a LiveSet in a similar way. The rest of the controller is fairly simple and similar to the snippet above.

The draw method uses a service provided by the loopback-angular-sdk to create additional points in the drawing. This data is streamed to other browser clients.

$scope.draw = function(e) {
  if($scope.drawing) {
    Circle.create({
      x: e.offsetX,
      y: e.offsetY,
      r: Math.floor(10 * Math.random())
    });
  }
}

Streaming Chart

The streaming chart does not use the LiveSet class at all. It demonstrates how to stream data from the server to a client.

var src = new EventSource('/api/process/memory');
var changes = createChangeStream(src);

changes.on('data', function(update) {
  // add the new data to the chart
});

See the entire chart example code.

Creating the Colors Example

Step 1: Dependencies

You will need the following node modules:

  • loopback
  • your favorite gulp or grunt plugins
  • gulp-loopback-angular (or the grunt version)

Also the following bower packages:

  • angular
  • angular-resource
  • angular-live-set

This tutorial assumes you are aware of setting up a basic angular application and its dependencies. You can use gulp or grunt or nothing at all.

Once you have your angular application running in a browser including the dependencies mentioned above, you can start using the lbServices and LiveSet modules to build the application.

Step 2: The API

This example was created first by running lb app. If you are unfamiliar with creating LoopBack apps read more about it here.

Once you have the LoopBack API scaffolded, you can add a model. We’ll start with a simple Color model just to get some data on the page.

lb model

Create the property val. Select string for the type. Add another property named votes. This should be a number.

Generate your lb-services.js angular module using the loopback-angular-sdk. This will give you access to the Color resource in your angular app. Make sure you include the script tag and register the module as an angular dependency for the lbServices module (generated by loopback-angular-sdk). You also must include the source for the ngResource module (which you should have installed as part of step 1).

Step 3: The Controller

Now that you have a Color model API and the angular-live-set module available from your angular app, you can create a simple controller for interacting with the Color data.

Start with a simple template that renders an array of color objects. I’ll assume you know how to do this. The template should look a bit like this:

<div ng-controller="ColorCtrl">
  <div ng-repeat="color in colors">
    <button
      ng-click="upvote(color.id)"
      style="background: "></button>
  </div>
</div>

Within our controller we need to create a LiveSet of colors as well as implement the createColor() and upvote() methods. It should look something like this.

function ColorCtrl($scope, createChangeStream, LiveSet, Color) {
  $scope.upvote = function(id) {
    Color.upvote({id: id});
  }

  $scope.newColor = 'red';

  $scope.createColor = function() {
    Color.create({val: $scope.newColor, votes: 0});
  }
}

And in our model source code we need to add the upvote method:

Color.upvote = function(id, cb) {
  Color.findById(id, function(err, color) {
    if(err) return cb(err);
    color.votes += 1;
    color.save(cb);
  });
};

Color.remoteMethod('upvote', {
  isStatic: true,
  accepts: {arg: 'id', type: 'number'}
});

Step 4: The LiveSet

The last step is to add the actual live set.

// this should be added to our controller
var changeStreamUrl = '/api/colors/subscription?_format=event-source';
var src = new EventSource(changeStreamUrl);
var changes = createChangeStream(src);
var set;

Color.find().$promise.then(function(colors) {
  set = new LiveSet(colors, changes);
  $scope.colors = set.toLiveArray();
});

The code above creates a LiveSet from a ChangeStream. The LiveSet is a read only collection of data. The items in the set will be updated as changes are written to the ChangeStream.

Since the change stream was created with an EventSource the changes will be written from the server as they are made. This will keep the data in the LiveSet up to date.

Also, the LiveSet will make sure that changes are applied to the $scope. This means for many use cases, you can create a LiveSet as a view of the data and use the model api (eg. Color) to modify the data. Once the change has been made on the server, the change will be made to your LiveSet.

Compatibility

EventSource is not available in all browsers. However, there are several polyfills available.

Run the Examples

Install the dependencies:

npm install && bower install
# make sure you have gulp installed globally... or
npm install gulp -g

Event streams don’t work with Node compression. To disable compression, delete the entry from server/middleware.json so it looks like this:

...
"compression": {
  "enabled":false
},
...

Build and run the example:

gulp serve

Open two separate browser windows and navigate to http://localhost:3000 in both.


More LoopBack examples