A few weeks ago, we posted our using PubNub with AngularJS SDK for Real-time which is a fast-growing and highly productive library for web application development in JavaScript. Since then, a few awesome things have happened:
- AngularJS continues to get more and more popular, and its pace of innovation shows no signs of slowing down (!)
- A ton of developers have integrated the PubNub AngularJS library into their apps and have given us awesome feedback directly to improvements
- Lastly and most importantly for the purposes of this blog, PubNub has released a huge new set of improvements to its Presence API, and those updates are now integrated into the AngularJS library
The new presence updates make it possible to add extended metadata to user and device connections, for example, "firstName", "lastName" and "location" for a user, or "machine id" or "device id" in the case of a computer system or mobile device. Note - these choices are just arbitrary, you can choose whatever fields you want for your application!
The PubNub AngularJS SDK should look familiar to experienced developers in Angular app development as well as to folks who have explored the PubNub API a bit. For this blog entry, we'll presume you are somewhat familiar with the ideas from an earlier PubNub AngularJS SDK Blog, at least enough to get started. If you like what you see here, you can jump right into a live version of the app at http://pubnub.github.io/angular-js/#/chat or the source code at https://github.com/pubnub/angular-js/ .
Let's take a look at the contents of http://pubnub.github.io/angular-js/index.html , the main entry point for the application.
Here are the script includes you'll need to get started:
<script src="http://cdn.pubnub.com/pubnub.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
<script src="http://pubnub.github.io/angular-js/scripts/pubnub-angular.js"></script>
The web app is Angular-enabled with an ng-app attribute:
<body ng-app="PubNubAngularApp">
The code for our app lives in:
<script src="http://pubnub.github.io/angular-js/scripts/app.js"></script>
The app requires a dependency on the PubNub Angular library (pubnub.angular.service, defined in pubnub-angular.js):
angular.module('PubNubAngularApp', ["pubnub.angular.service"])
The code for our controllers lives in:
<script src="http://pubnub.github.io/angular-js/scripts/controllers/main.js"></script>
Once that's set, the PubNub service can be injected into the controller by name!
.controller('JoinCtrl', function($scope, PubNub) { ... });
Publishing to channels is trivial - just use the PubNub.ngPublish()
method.
$scope.publish = function() {
PubNub.ngPublish({
channel: $scope.selectedChannel,
message: $scope.newMessage
});
};
Subscribing to channels is accomplished by calling the PubNub.ngSubscribe()
method. After the
channel is subscribed, the app can register root scope message events by calling $rootScope.$on
with the "event name" string returned by PubNub.ngMsgEv(channel)
.
$scope.subscribe = function() {
...
PubNub.ngSubscribe({ channel: theChannel });
...
$rootScope.$on(PubNub.ngMsgEv(theChannel), function(event, payload) {
// payload contains message, channel, env...
console.log('got a message event:', payload);
});
}
Here's where it gets interesting - with the NEW presence extensions, it's easy to associate attributes to your connection - as simple as:
$scope.subscribe = function() {
...
PubNub.ngSubscribe({
channel: theChannel,
state: {
"firstName" : $scope.user.firstName,
"lastName" : $scope.user.lastName,
"favoriteColor" : $scope.user.faveColor
}
});
...
}
This makes it much easier to create presence lists, rosters, and location-aware
applications. For example, a location-aware application might use the NEW ngState()
call to continuously update location metadata as follows:
PubNub.ngState({
channel:theChannel,
state: {
"firstName":$scope.user.firstName,
"lastName":$scope.user.lastName,
"lat":$scope.user.position.lat,
"lon":$scope.user.position.lon
}
});
The location fields "lat" and "lon" can then be used to display markers on the application's map display. How cool is that?
The PubNub Presence API makes it very easy to build presence-aware applications -- without the Presence API, you'd have to track all of the join/leave/timeout events yourself on the server side. Which is really tough if you're building a pure JS web application with no server side! Presence fixes that.
To keep things simple, wiring up Presence events using the PubNub AngularJS API is very similar to wiring up Message events. It all boils down to registering an event handler callback for the presence events:
PubNub.ngSubscribe({ channel: theChannel });
...
$rootScope.$on(PubNub.ngPrsEv(theChannel), function(event, payload) {
// event is AngularJS event, payload contains PubNub Presence event
console.log('got a presence event:', payload);
});
...
PubNub.ngHereNow({ channel: theChannel });
In this case, PubNub.ngPrsEv(theChannel)
returns the "event name" string that identifies
presence events for the specified channel.
The presence event payload contains a bunch of useful information for
your app: the channel and PubNub event itself. In the case of a single-user event (which you
can tell by the presence of the 'uuid' field, payload.event
contains action (join/leave/timeout),
occupancy (number of users in the channel), timestamp, and uuid of the relevant user. Now,
with the NEW advanced presence API, it also includes a data
attribute (accessible
through payload.event.data).
In the case of a multi-user event (such as the one triggered by ngHereNow()
), the
payload.event
contains the occupancy count as well as a 'uuids' field (note pluralization)
which contains the list of current user ids. Now, with the NEW advanced presence API, each
uuid is an object that includes a uuid
field and a state
field which includes
the extended attributes. Pretty nifty!
In addition to the callback-based API, there is also a convenient collection-based API
that keeps track of channel membership automatically. To obtain the list of users, just call
the ngListPresence()
function with the name of the channel you'd like to list. Of course,
you'll want to already be subscribed to the channel and initialized the 'here now' status
as in the example below.
PubNub.ngSubscribe({ channel: theChannel });
PubNub.ngHereNow({ channel: theChannel });
...
allTheUsers = PubNub.ngListPresence(theChannel);
Often times, we combine both approaches to make sure that our Angular views always have the most up-to-date user list:
PubNub.ngSubscribe({ channel: theChannel });
PubNub.ngHereNow({ channel: theChannel });
...
$rootScope.$on(PubNub.ngPrsEv(theChannel), function(event, payload) {
$scope.userList = PubNub.ngListPresence(theChannel);
});
But here's the kicker - to make things extra awesome for Angular development, we
also keep track of the presence extended attributes for the connected users in
each channel. You can get it all simply by calling ngPresenceData
and passing
in the channel name. This is pretty sweet:
PubNub.ngSubscribe({ channel: theChannel });
PubNub.ngHereNow({ channel: theChannel });
...
$rootScope.$on(PubNub.ngPrsEv(theChannel), function(event, payload) {
$scope.userDataMap = PubNub.ngPresenceData(theChannel);
});
This gets the cached map of user UUIDs to extended attributes and stores it to the Angular scope. Now, every time the presence information changes, your app can access it via the $scope.userDataMap collection.
And just like that, your app is wired for presence!
All of this is really cool, but sometimes it's hard to keep track of what users are subscribed to what channels in the application. Even with the cool presence helper functions in the PubNub Angular SDK, it's not possible to know what users are present in what channels if you're not subscribed to them.
With the new presence API, that all changes! There's a nifty new ngWhereNow()
function you can call to get access to global channel subscription information
for a given user UUID.
PubNub.ngWhereNow({
uuid:theUserId,
callback:function(){console.log(arguments)}
});
The response contains a channels
list of channel names for the subscriber,
which can come in handy when you need to see exactly where a user's at!
In this blog entry, we had fun showing you how to integrate your angular app with the advanced presence features of the PubNub AngularJS library. We hope you find this information to be useful -- it is really cool to see the number of PubNub and AngularJS applications growing over the past few weeks!
The PubNub API has many more features we didn't cover in this blog post, but which are explained in detail in the GitHub API Guide and Reference. The documentation walks you through additional topics which really enhance your real-time-enabled web application.
In future blog posts, we'll cover even more outstanding features of the PubNub Angular API. In the meantime, please give the AngularJS integration a try, have fun, and reach out if you have ideas visit GitHub pubnub/angular-js. Or, do you need a hand (help@pubnub.com)!