Good News! We've launched an all new Chat Resource Center.
We recommend checking out our new Chat Resource Center, which includes overviews, tutorials, and design patterns for building and deploying mobile and web chat.
Angular 2 is the new version of Google's popular MV* framework for building apps in the browser and beyond. In this blog series, we'll cover how to build real-time functionality into web and mobile apps with the Angular 2 SDK for PubNub.
In this part, we'll use our core Publish/Subscribe feature to build a basic real-time chat app, in this case, sending and receiving data, and saving that message history with Storage & Playback. In our next part, we walkthrough more advanced features of the PubNub API such as Presence (online/offline detection) and Custom State.
Angular 2 and PubNub Overview
We're guessing that you're here because you have an existing AngularJS application you'd like to migrate to Angular 2, or a green field application you'd like to build in Angular 2 from the ground up. Here's a quick sketch of the Angular 2 features we're tracking so far:
- Syntax: If you haven't worked with Angular 2 just yet, the first thing you'll probably notice is that the syntax changes are a bit surprising. It should be for the better though, since the standard syntax will reduce library code duplication and special cases and make it easier to build tool support.
- TypeScript: The next thing you'll likely notice is that TypeScript has pretty much taken over the Angular 2 world (You don't have to use it, but it would probably be best to start getting familiar with it because the pure JavaScript documentation is lagging).
- Components, not Controllers: That's right, Components have taken over in the new model. This is probably for the best, as browser support for the new Web Components standards proliferate. Components are neat because they encapsulate data, behavior, and UI into one nifty self-contained package.
- Modularity: With the adoption of components, folks went a little crazy modularizing all of Angular 2's dependencies. In our early mind, we think it's a little over the deep end.
All in all, we feel like Angular 2 presents a bunch of improvements over AngularJS. Not that it'll feel awesome while re-learning or migrating all the old apps, but we do feel like the investment in learning Angular 2 (and TypeScript) will improve things over time.
What's New in the PubNub JavaScript v4 SDK
Okay, so we know we want to build an application with Angular 2, how do we get there? The first non-Angular 2 dependency we'll need is the PubNub JavaScript SDK.
PubNub and JavaScript work really well together because the PubNub JavaScript SDK has been battle-tested over the years across a huge number of mobile and backend installations. The SDK is currently on its 4th major release, which features a number of improvements such as isomorphic JavaScript, new network components, unified message/presence/status notifiers, and much more. Since we're using the PubNub Angular 2 SDK, our UI code must use the PubNub JavaScript v4 API syntax.
So, what exactly are those new features all about? Here's the quick run-down so you know what you're getting:
- Isomorphic JavaScript: This means all applications reap the performance and quality benefits of unified JavaScript library that works across web, mobile, and backend installations.
- New Networking Stack: As part of the isomorphic migration, PubNub improved the networking stack with cleaner dependencies.
- Unified Event Model: Responding to asynchronous events from status/messages/presence just got a lot easier.
- ES6 Classes:. Just in time for Angular 2!
- Cryptography Improvements:. Reduced footprint for improved memory/CPU usage.
- Reconnection: New policies to handle flaky network connections on mobile clients.
In addition, there are a few migration tips you should keep in mind for V3 versus V4:
- PUBNUB is now PubNub. The global PubNub instance is now exposed via the PubNub variable.
- Initialization.
PUBNUB.init()
has been replaced bynew PubNub({...})
. - Parameters: snake_case is now camelCase. So make sure your
publish_key
gets changed topublishKey
! - Listeners. Previously, there were callbacks passed into the different methods. Now we call
addListener()
to register callbacks. - Core Methods. Previously, core methods took callbacks. Now, methods have standardized on passing a data object as the first parameter, and a callback as the second parameter.
By now, you might be wondering about how all this JavaScript is distributed. The PubNub JavaScript SDK is distributed via Bower or the PubNub CDN (for Web) and NPM (for Node), so it's easy to integrate with your application using the native mechanism for your platform. In our case, it's as easy as including the CDN link from a script
tag.
What's New in the PubNub Angular 2 SDK
So first off, you'll want to remember that the Angular 2 SDK will be using the PubNub JavaScript V4 API (just in case you find yourself copy and pasting any V3 configuration or code into your app – beware)!
The new Angular 2 API is based here in GitHub, and is also available via NPM as pubnub-angular2
. If the success of PubNub and AngularJS is any indication, the Angular 2 documentation and tutorials should be growing quickly in the months ahead!
For folks who are familiar with the AngularJS SDK, here's an overview of what's new in the Angular 2 SDK:
- Multiple Instances: It's now possible to instantiate multiple PubNubAngular services with different IDs (for example, if you have to connect multiple apps or different permissions or encryption parameters).
- Initialization: This may seem a bit strange, but you call
pubnub.init({...})
in Angular 2 instead of using the updated V4new PubNub()
syntax. - Events: There are now many more targeted methods for determining which events get fired by status/presence/messages.
- Stack Model for Messages: The
pubnub.getMessage()
function returns a dynamic collection that includes the current history of messages received on the channel. - History and Autoload: The
pubnub.history()
method uses the updated V4 object format. In addition, thepubnub.subscribe()
method takes anautoload:X
parameter that will load X messages automatically, where X is a value from 1 to 100.
Overall, the new Angular 2 SDK feels pretty natural in building up a new real-time web application. If you have any ideas for suggestions, please drop us a line!
Obtaining your PubNub Developer Keys
You'll first need your PubNub publish/subscribe keys. If you haven't already, sign up for PubNub. Once you've done so, go to the PubNub Admin Portal to get your unique keys.
The publish and subscribe keys look like UUIDs and start with “pub-c-” and “sub-c-” prefixes respectively. Keep those handy – you'll need to plug them in when initializing the PubNub object in your HTML5 app below.
Note: for this article, you'll want to make sure to enable the Storage and Playback feature in your PubNub Application configuration to take advantage of the history()
feature.
Diving into the Code – the User Interface
You'll want to grab these 94 lines of HTML & JavaScript and save them to a file called pubnub_angular2_basic.html
.
The first thing you should do after saving the code is to replace two values in the JavaScript:
- YOUR_PUB_KEY: with the PubNub publish key mentioned above.
- YOUR_SUB_KEY: with the PubNub subscribe key mentioned above.
If you don't, the UI will not be able to communicate with anything and probably clutter your console log with entirely too many errors. For your convenience, this code is also available as a Gist on GitHub, and a Codepen as well. Enjoy!
Dependencies
First up, we have the JavaScript code & CSS dependencies of our application.
<!DOCTYPE html> <html> <head> <title>Angular 2</title> <script src="https://unpkg.com/core-js@2.4.1/client/shim.min.js"></script> <script src="https://unpkg.com/zone.js@0.7.2/dist/zone.js"></script> <script src="https://unpkg.com/reflect-metadata@0.1.9/Reflect.js"></script> <script src="https://unpkg.com/rxjs@5.0.1/bundles/Rx.js"></script> <script src="https://unpkg.com/@angular/core/bundles/core.umd.js"></script> <script src="https://unpkg.com/@angular/common/bundles/common.umd.js"></script> <script src="https://unpkg.com/@angular/compiler/bundles/compiler.umd.js"></script> <script src="https://unpkg.com/@angular/platform-browser/bundles/platform-browser.umd.js"></script> <script src="https://unpkg.com/@angular/forms/bundles/forms.umd.js"></script> <script src="https://unpkg.com/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js"></script> <script src="https://unpkg.com/pubnub@4.3.3/dist/web/pubnub.js"></script> <script src="https://unpkg.com/pubnub-angular2@1.0.0-beta.8/dist/pubnub-angular2.js"></script> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" /> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" /> </head>
For folks who have done front-end implementation with Angular 2 before, these should be the usual suspects:
- CoreJS ES6 Shim, Zone.JS, Metadata Reflection, and RxJS : Dependencies of Angular 2.
- Angular 2 : core, common, compiler, platform-browser, forms, and dynamic platform browser modules.
- PubNub JavaScript client: to connect to our data stream integration channel.
- PubNub Angular 2 JavaScript client: provides PubNub services in Angular 2 quite nicely indeed.
In addition, we bring in the CSS features:
- Bootstrap: in this app, we use it just for vanilla UI presentation.
Overall, we were pretty pleased that we could build a nifty UI with so few dependencies. And with that… on to the UI!
The User Interface
Here's what we intend the UI to look like:
The UI is pretty straightforward – everything is inside a main-component
tag that is managed by a single component that we'll set up in the Angular 2 code.
<body> <main-component> Loading... </main-component>
Let's skip forward and show that Angular 2 component template. The h3
heading should be pretty self-explanatory, along with the tag that displays the userId
. We provide a simple text input for a chat message, as well as a button to perform the publish()
action to send the message out on the PubNub channel.
<div class="container"> <h3>Welcome to Channel: {{ channelName }}</h3> <small>You are: <b>{{userId}}</b></small> <hr/> <p>Enter a new message:</p> <input type="text" [(ngModel)]="newMessage" /> <button class="btn btn-primary" (click)="publish()">Send!</button> <br/> <br/> <ul class="list-unstyled"> <li *ngFor="let item of messages">{{ item.message }}</li> </ul> </div>
The component UI consists of a simple list of messages; We iterate over the messages in the component scope using a trusty ngFor
. Each message includes the chat text (in your application, you may choose to use a structured JSON message instead).
And that's it – a functioning real-time UI in just a handful of code (thanks, Angular 2)!
The Angular 2 Code
Right on! Now we're ready to dive into the Angular 2 code. It's not a ton of JavaScript, so this should hopefully be pretty straightforward.
The first lines we encounter set up our application (with a necessary dependency on the PubNub AngularJS service) and a single component (which we dub main-component
).
<script> var app = window.app = {}; app.main_component = ng.core.Component({ selector: 'main-component', template: `...see previous...`
The component has a constructor that takes care of initializing the PubNub service and configuring the channel name, (random) user ID and message-related variables.
}).Class({ constructor: [PubNubAngular, function(pubnubService){ var self = this; self.pubnubService = pubnubService; self.userId = 'User_' + Math.round(Math.random() * 1000); self.messages = []; self.newMessage = ''; self.channelName = 'angular2-chat';
Early on, we initialize the pubnubService
with our credentials.
pubnubService.init({ publishKey: 'YOUR_PUB_KEY', subscribeKey: 'YOUR_SUB_KEY', uuid: this.userId });
We subscribe to the relevant channel and configure an event handler that will unshift()
any incoming messages into the self.messages
array.
pubnubService.subscribe({channels: [self.channelName], triggerEvents: true, withPresence: true}); pubnubService.getMessage(this.channelName, function(msg) { self.messages.unshift(msg); });
To implement the persistence function, we call history()
which returns a Promise. To handle the Promise, we call the then()
function with a callback that reads the messages
collection from the incoming history event into the self.messages
collection.
Note that we use x.entry
because that's the new attribute for message data in the Persistence API.
pubnubService.history({channel: self.channelName, count:50}).then(function(msg) { msg.messages.forEach(function(x) { self.messages.unshift({message:x.entry}); }); }); }],
We also create a publish()
event handler that performs the action of publishing the new message to the PubNub channel.
publish: function(){ if (this.newMessage !== '') { this.pubnubService.publish({channel: this.channelName, message: '[' + this.userId + '] ' + this.newMessage}); this.newMessage = ''; } } });
Now that we have our new component, we can create a main module for the Angular 2 app that uses it. This is pretty standard boilerplate that configures dependencies on the Browser and Forms modules and the PubNubAngular service.
app.main_module = ng.core.NgModule({ imports: [ng.platformBrowser.BrowserModule, ng.forms.FormsModule], declarations: [app.main_component], providers: [PubNubAngular], bootstrap: [app.main_component] }).Class({ constructor: function(){} });
Finally, we bind the application bootstrap initialization to the browser DOM content loaded event.
document.addEventListener('DOMContentLoaded', function(){ ng.platformBrowserDynamic.platformBrowserDynamic().bootstrapModule(app.main_module); });
We mustn't forget close out the HTML tags accordingly.
}); </script> </body> </html>
Not too shabby for about 94 lines of HTML & JavaScript!
Conclusion
Thank you so much for joining us in the first part of our Angular 2 series! Hopefully it's been a useful experience learning about what's new in the JavaScript and Angular 2 worlds. In future articles, we'll dive deeper into additional PubNub APIs like Presence and User State.
Stay tuned, and please reach out anytime if you feel especially inspired or need any help!