Howdy and welcome to the second part of these screencasts dealing with real-time events. In this episode we’ll implement much of the client side portion of our code. As I said at the end of the last episode, you can implement your front-end, however, you’d like. I’m just learning the front-end so I wanted to start with server-side views and then refactor what I’ve done to include a framework like backbone to transition into a single page application. That, however, is for another day and here we’ll manipulate the DOM within our server-side views.
So let’s go back to the app.js file located in the
assets/linker/js directory and our event listener for the event message. As you may recall, within this file we’ve established a connection with the socket server, subscribed to our User model’s “class” room and “instance” room via
socket.get(). And we’re now awaiting message via
Now in addition to logging this message I want to make changes to the DOM depending upon the contents of the message. To make the code cleaner, I’m going to define the callback function outside the event listener.
Once again I’m not the most imaginative person when it comes to function names and as proof of this I’m going to name the callback
cometMessageReceivedFromServer. This will be the method that will route our messages depending upon the model that is being updated. And we’ll define it down here at the bottom of the app.js file. I’m still going to log the message for debug purposes but now I’m going to check if the message is coming from the user model and if it is I’m going to call a new custom method called updateUserInDom and pass it the userId and the message.
updateUserInDom is going to determine which page will ultimately receive the changesand route it to the appropriate method for that page. So in this case, the receiving page is
/user or the User Administration Page and since the action or verb is update, we’re going to route the message to the
updateUser method of an object called IndexPage. Remember these are all custom methods that I’m creating and have nothing to do with sails.
updateUser method is where we’ll update the DOM to display the
icon-online.png or icon-offline.png depending upon the value of loggedIn. If you take a look at the index.ejs file under the
views/user directory, I’m populating each row of DOM with two custom data attributes, data-id and data-model. These are then used as jquery criteria for identifying DOM elements. So we’ll find the row of the user id that we want to change and then replace the image src with the correct icon. Let’s see if it works
As you can see, the login status icon changes immediately when another user logs in or out.
What about when a new user is created? We want to update the User Administration Page with the new user or deleted user and their login status.
To do this we’ll use the
publishCreate and publishDestroy methods. So we head over to the create action of the user controller and insert the
publishCreate method passing the created user as an argument. Then we’ll look at the destroy action and insert our
publishDestroy method passing the id of the user that was destroyed. That’s it for the server-side. Back to the client and our app.js file. We’ll start at our old friend
cometMessageReceivedFromServer method. From there we’ll proceed to the
updateUserInDom method where the receiving page will again be
/user or the User Administration page. But here we’ll two cases to our switch statement. One for the create action and one for the destroy action. For the create action we’ll use the
addUser method. To clean things up and to show some functionality I’m going to use a template using the underscore library. So let’s take a look at the template, which I’ve stored in the
This template represents one row of the User Administration Page. Before using this template there were a few things I needed to set-up. The first was to add the underscore library to
linker/assets/js directory. Next, I made a slight change to the Gruntfile, changing the default template files to inject, from html to ejs. Finally, because we are using a hidden form for the delete button action, we need to have access to the csrf token. Since the template is added after the index.ejs page has been rendered on the server, we needed a way to get at the token.
There are several different ways this can be done (including make an ajax call to the server via a
/csrfToken route). However, I decided to make a change to the layout.ejs file appending the csrf token to my own namespaced attribute on the global window object. That way when the layout.ejs file is rendered, my object will be appended to the page.
So back in the app.js file I’ve built up an object called obj with the user plus the csrf token we obtained from the layout.ejs file.
Here, I’m using jquery to grab the last tr on the page and apply the template after that last tr tag, passing in the necessary data for the template in our obj object.
But what about when a user is deleted? That’s a lot easier. We’ll add the
destroyUser method and use jquery to find the appropriate user and remove that row from the DOM.
Woah…let’s see if all that stuff worked. I’ll restart the server and log myself in the first browser and create a user in the second browser and great…the user was added to the DOM with the correct login status. Now I’ll log out and login as another user, and this time delete the user we just created…and both sides updated like we wanted.
There’s one more thing to add. Each time the server comes up we want to make sure that the online attribute of each user is set to false. For that we can the sails bootstrap config file. Because I used an empty object as the first argument, all the users will be updated. The second argument is the attribute I want to update, in this case online is set to false. Finally I’ll trigger the callback back to the middleware stack. Now every time you start the server, users online attribute will be reset to false.
That was a long one. For those of you who made it through, I hope it was informative and as always thanks for watching.