Now that we have built a basic chat room it is time to give our users some more functionality. In part two of this series we will expand on part one by managing multiple rooms, showing users a history of previous messages, and showing what users are in the room.
2. This is the second of a three-part series explaining how to build a multi-user messaging application
using jQuery Mobile and PubNub. You can read the series overview here.
Now that we have built a basic chat room it is time to give our users some more functionality. In part
two of this series we will expand on part one by managing multiple rooms, showing users a history of
previous messages, and showing what users are in the room.
As a quick note, from here on out I will be showing fragments of the final source code that will not
work by copy and pasting. This is in order to focus on the learning points and keep the code
examples shorter. If you would like the fully working version please check out the final version of this
demo at https://github.com/dristic/pub-messenger.
3. Joining Multiple Rooms
Our app would be complete if every person wanted to talk to everyone else using the app at the same time in one
giant chat room. Unfortunately for us people always want more features. The first feature we will add is the ability to
join different chat rooms and keep a list of the ones that the user has joined.
We will now have two pages to our app and use jQuery Mobile’s page navigation feature to switch between them. This
will keep everything running in a single page meaning we can build on top of all the previous part’s code. The UI for
this page is pretty simple. It includes a list view, an input box, and a button which are all native jQuery Mobile
components.
<!-- Chat List Page -->
<div data-role="page" id="chatListPage" data-theme="c" class="type-chat-list">
<div data-role="header">
<h1>Current Chats</h1>
</div>
<div data-role="content">
<input type="text" name="name" id="chatRoomName" placeholder="Chat Room Name" />
<a href="#" id="newChatButton" data-role="button">Join New Chat</a>
<br />
<ul data-role="listview" data-split-icon="delete" data-split-theme="c" id="chatList">
<!-- <li><span class="username">User123:</span>This is my message.</li> -->
</ul>
</div>
</div>
4. Now we use some simple JavaScript to display a list of subscriptions when the user navigates to this page. The list is
stored as an array of strings globally throughout the application. In the final version I decided to use localStorage to
keep the state of this array between application uses. This even works on mobile devices for some quick and easy
device side storage and still keeps our app cross platform.
var chatChannel = '',
chatRoomName = $('#chatRoomName'),
charListEl = $('#chatList'),
subscriptions = [],
pages = {
chatList: $("#chatListPage"),
chat: $("#chatPage")
};
function onChatListOpen () {
chatListEl.empty();
for(var i = 0; i < subscriptions.length; i++) {
var chatName = subscriptions[i],
chatEl = $("<li><a href='#chatPage' data-channel-name='" + chatName + "'>"
+ chatName
+ "</a><a href='#delete' data-rel='dialog' data-channel-name='" + chatName + "'></a></li>");
chatListEl.append(chatEl);
chatListEl.listview('refresh');
}
newChatButton.off('click');
newChatButton.click(function (event) {
if(chatRoomName.val() !== '') {
chatChannel = chatRoomName.val();
$.mobile.changePage(pages.chat);
}
});
};
5. The other HTML5 goodness I am using is the data- attributes on each link to keep the channel name. This allows me
to pass data between my views without doing too much work. I can simply navigate to the chat room view and
check for any data- attributes coming from the link source.
The final few things here is creating a new chat button that accepts a room name from the input box and navigates
to the chat room view. Also do not forget to create a back button on the chat room view as well as handle coming
from the link versus the new room button. I also make sure to unsubscribe from the channel when going back to the
chat room list view.
6. History
Another great feature we can add is seeing a history of
recent messages when the user enters a chat room.
PubNub has an additional feature for history that allows
you to get a number of previous messages sent in any
channel. The call easily integrates with our current app
by looping through the list of previous messages and
then sending them through our message handler as if we
just got a message from subscribe.
pubnub.history({
channel: chatChannel,
limit: 100
}, function (messages) {
messages = messages[0];
messages = messages || [];
for(var i = 0; i < messages.length; i++) {
handleMessage(messages[i], false);
}
$(document).scrollTop($(document).height());
});
7. Presence
The final feature we want to add is a user list for seeing who is
currently chatting in the room we are in. Our strategy for this is going
to be using a combination of unique ids and presence from our
PubNub API to handle all the back end work for us.
The idea for the user interface would be a two column layout that hides
the user list on mobile phones. This came from the jQuery Mobile
documentation site which has a left column navigation on larger
screens and a collapsed version on smaller ones. This will also stay in
line with the idea of being cross platform and being able to build to
multiple devices at once. I used parts of the extra bit of css found
here.
http://jquerymobile.com/demos/1.2.0/docs/_assets/css/jqm-docs.css
on the jQuery mobile documentation that allows for a content-primary
and content-secondary areas which handle most of this for us. From
there it was a lot of tweaking to get the final version that exists in the
Github repository. Here is the updated html for the chat page:
9. Surprisingly the hardest part was actually getting the user interface to be responsive. Actually wiring this up with
JavaScript was delightfully simple. First off I created a home page with an input box which allows the user to input a
chat room name. I then capture this and add send this as the UUID with the PubNub connection like so:
PUBNUB.init({
publish_key: 'demo',
subscribe_key: 'demo',
uuid: username // This is where the entered username goes.
});
10. Now we add a presence listening function in the subscribe call. This will get fired every time a user in the same
channel does an action such as joining the channel or leaving. Since all we care about for now is joining or leaving we
check and see what the message action is and either remove or add the username from our user list UI. PubNub
takes care of the rest!
After all those juicy features we now come to the end of part two. We gave our demanding users some more features
including joining different chat rooms, seeing chat history, and seeing what other users are currently chatting. I will
wrap this up in Part 3 where I will explain how to package everything up with PhoneGap, tying up the responsive UI,
and future thinking on scalability and performance.
var users = [],
userList = $("#userList");
pubnub.subscribe({
channel: chatChannel,
message: handleMessage, // Our global handle message function
presence: function(message, env, channel) { // This gets called on user leave / enter
if (message.action == "join") {
users.push(message.uuid);
userList.append("<li data-username='" + message.uuid + "'>" + message.uuid + "</li>");
} else if (message.action == "leave") {
users.splice(users.indexOf(message.uuid), 1);
userList.find('[data-username="' + message.uuid + '"]').remove();
}
userList.listview('refresh');
}
});