Enabling Users to Create Private Chat via Private Channels
In this tutorial, we’ll continue talking about creating multiple channels to spawn chatrooms on demand. In this case, we’ll walk you through how to enable users to spawn private chat with another user on demand. This way, users can select who they want to chat with, then initiate a private chat with that user.
We’ve now covered both building a multiplayer game lobby with a chatroom and the different ways we can use matchmaking to connect two different users. Here’s what we’ve covered so far:
- Part One: Series Overview and Building a Multiplayer Game Lobby
- Part Two: Adding Users and Usernames
- Part Three: Getting a List of Online Users
- Part Four: Random Matchmaking of Users
- Part Five: Skill-based Matchmaking of Users
- Part Six: Matchmaking Algorithm: Enabling Users to Challenge Other Players
- Part Seven: Create Chatrooms and Multiple Channels On Demand Tutorial
- Part Eight: Preparing for Private Chatrooms and Refactoring via Private Channels
- Part Nine: Creating Private Chat Requests with Popup Alerts
Refactoring to Object Oriented Patterns
Now that we can spawn chatrooms on demand, let’s allow one user to spawn a new private chat on a private channel with another user.
You’ll first need to sign up for a PubNub account. Once you sign up, you can get your unique PubNub keys in the PubNub Developer Portal. Once you have, clone the GitHub repository, and enter your unique PubNub keys on the PubNub initialization, for example:
Up until our most recent tutorial, our code has been only functional. Like last time, our code this time will be object oriented. If we added the ability to spawn chatrooms to our old functional code, things would get confusing very quickly. We’ll start by converting our functional code into object oriented code. This will make it easier for us to manage user to user communications.
We’re going to make use of what’s known as the Object Constructor Pattern. Let’s start with our Alarm closure example from earlier.
What if we wanted to expose the
name variable from outside the
Alarm() function? We use the
this keyword to expose the variable outside of our function.
The “new” Keyword
Notice the changes made to our last lines. Specifically how we changed
- The new operator creates an instance of a user-defined object type or of one of the built-in object types that has a constructor function.
Instead of simply executing
Alarm(), we call
new_alarm = new Alarm() which assigns the instance of the function to the variable
We need to use the word
new because it instructs the the value of
this to be bound to the context of the function. If you forget to use the
new keyword, this will be assigned to the global object.
- If you forget to include the new prefix when calling a constructor function, then this will not be bound to the new object. Sadly, this will be bound to the global object, so instead of augmenting your new object, you will be clobbering global variables. That is really bad. There is no compile warning, and there is no runtime warning.
Douglas Crockford has a great writeup of the object constructor pattern,
this, private and public methods and more.
So now let’s start refactoring our old challenge example into an Object Constructor pattern.
Self = This
Notice that instead of using
this directly, we assign
var self = this. This is because the
this variable will have a different value within nested functions. We want to ensure that we’re always referring to the
User context, so we store the context of
self so we can access it from inside any function.
return self; at the end of the function allows us to string function methods together. For example, we could call
Remove Data Tied to DOM
We also gain a huge organizational advantage switching to an object oriented pattern. We’re able to store references to the DOM elements within the objects themselves, allowing us to modify the page without actually selecting nodes by hand.
Instead of calling
$('#' + data.uuid).remove(); we can write:
a_user has stored the DOM node in
$tpl so we can access it directly instead of looking it up.
state. Now that we keep users in objects, we can keep the value of their state as a property. This means when we need to find an opponent for matchmaking, we can avoid using the
pubnub.here_now() call. We’ll already have a list of users and their state ready!
We’re going to support an unlimited number of users, so creating objects one at a time will quickly get messy. Instead, we’ll create a factory pattern that will keep track of our
User()s in an array.
The largest change to our app are the changes to
me. Instead of
me just representing a username, we’re going to make it into an object that turns the browser window into an extension of a
We start out by assigning the variable
self to a
new User() with a
randomName(). This means
Client() will be an extended from
User() and have all it’s properties like
We add a couple more methods to the Client:
onResponse(). These handle our challenge requests and responses. We only add them to our Client instead of every User as we don’t want to accidentally challenge or respond on behalf of another user.
Also, because the
Client() extends the
User() we can still get the client username from
me.uuid. We bind to the DOM events inside of the
App() object and then act on behalf of the
me object when fired.
Routing PubNub Requests
Last, we create an
App() object to initialize our application and handle incoming traffic.
It’s worth noting a couple additional changes to scope.
me turned into a global variable as is
Users and some of our global template elements. The function
randomName() is still available globally and our skill generator has been turned into
Full Refactored Code
Put it all together and we have the following.
Private Chat with Private Channels Demo
Check out the live demo below. It looks and behaves exactly as our previous example did, but the code has been organized into an object oriented pattern.
In our next blog post, we’ll talk about how to spawn private chatroom popups.