So far, each of the pages that we have rendered displays its viewModel
data perfectly, but that pesky sidebar still remains blank. We're going to fix this by creating a few modules for the sidebar content but implementing them as helper modules. These helper modules are those that will be used repeatedly by various parts of our application and don't necessary belong to the controller
folder or the server
folder. So, we'll just create a new home called helpers
and store these modules there.
First, we will create a module for the entire sidebar. This module will be responsible for calling multiple other modules to populate viewModel
for each section of the sidebar. As we are going to be populating each page's own viewModel
with data specifically for the sidebar, the sidebar
module's function will accept that original viewModel
as a parameter. This is so that we can append data to the existing viewModel
for each page.
Here we will be appending a sidebar
property (which is a JavaScript object) that contains properties for each of the sections of the sidebar.
To get started, first create a file named helpers/sidebar.js
and insert the following code:
var Stats = require('./stats'), Images = require('./images'), Comments = require('./comments'), module.exports = function(viewModel, callback){ viewModel.sidebar = { stats: Stats(), popular: Images.popular(), comments: Comments.newest() }; callback(null, viewModel); };
In the preceding code, you can see that we first required a module for each section of the sidebar. The existing ViewModel
for any given page that displays the sidebar is the first parameter to the function. We add a sidebar
property to viewModel
and set values for each property by calling the module for each section of the sidebar. Finally, we execute a callback that was passed in as the second parameter to the sidebar
module. This callback is an anonymous function that we will use to execute the rendering of the HTML page.
Let's update the home
and image
controllers to include a call to the sidebar
module as well as defer rendering the HTML template for each page to the callback for the sidebar
module.
Edit controllers/home.js
and take the following line of code:
res.render('index', viewModel);
And replace it with this new block of code:
sidebar(viewModel, function(viewModel) { res.render('index', viewModel); });
Again, notice how we are executing the sidebar
module and passing the existing viewModel
as the first parameter and a basic anonymous function as a callback for the second parameter. What this is doing is waiting to render the HTML for the view until after the sidebar has completed populating viewModel
. This is because of the asynchronous nature of Node.js. Suppose we wrote the code in the following way instead:
sidebar(viewModel); res.render('index', viewModel);
Here, it's quite likely that the res.render
statement will execute before sidebar
has even finished doing any work. This is going to become very important once we introduce MongoDB in the next chapter.
Additionally, as we are now using the sidebar
module in each controller, be sure to require it at the top of both controllers by including the following code:
var sidebar = require('../helpers/sidebar'),
Now that our sidebar
module is complete, and it's being called from both controllers, let's finish the sidebar by creating each of the submodules that are required.
The stats
module is going to display a few random pieces of statistics about our app. Specifically, it will show the count for the total number of images, comments, views, and likes for the entire website.
Create the helpers/stats.js
file and insert the following code:
module.exports = function() { var stats = { images: 0, comments: 0, views: 0, likes: 0 }; return stats; };
This module is pretty basic and all it does is create a standard JavaScript object with a few properties for the various stats, each set initially to 0
.
The images
module is responsible for returning various collections of images. Initially, we will create a popular
function that will be used to return a collection of the most popular images on the website. Initially, this collection will simply be an array of image objects with the sample fixture data present.
Create the helpers/images.js
file and insert the following code:
module.exports = { popular: function() { var images = [ { uniqueId: 1, title: 'Sample Image 1', description: '', filename: 'sample1.jpg', views: 0, likes: 0, timestamp: Date.now }, { uniqueId: 2, title: 'Sample Image 2', description: '', filename: 'sample2.jpg', views: 0, likes: 0, timestamp: Date.now }, { uniqueId: 3, title: 'Sample Image 3', description: '', filename: 'sample3.jpg', views: 0, likes: 0, timestamp: Date.now }, { uniqueId: 4, title: 'Sample Image 4', description: '', filename: 'sample4.jpg', views: 0, likes: 0, timestamp: Date.now } ]; return images; } };
Similar to the images helper module, the comments
module will return a collection of the newest comments posted to the site. The idea of particular interest is that each comment also has an image attached to it so that the actual image for each comment can be displayed as a thumbnail while displaying the list of comments (otherwise, we lose context when we see a random list of comments with no related image).
Create the helpers/comments.js
file and insert the following code:
module.exports = { newest: function() { var comments = [ { image_id: 1, email: '[email protected]', name: 'Test Tester', gravatar: ' http://lorempixel.com/75/75/animals/1', comment: 'This is a test comment...', timestamp: Date.now(), image: { uniqueId: 1, title: 'Sample Image 1', description: '', filename: 'sample1.jpg', views: 0, likes: 0, timestamp: Date.now } }, { image_id: 1, email: '[email protected]', name: 'Test Tester', gravatar: 'http://lorempixel.com/75/75/animals/2', comment: 'Another followup comment!', timestamp: Date.now(), image: { uniqueId: 1, title: 'Sample Image 1', description: '', filename: 'sample1.jpg', views: 0, likes: 0, timestamp: Date.now } } ]; return comments; } };
Again, this is just a basic JavaScript array of objects with a few properties for each comment, one of which is an actual image and its properties (the image
property should look familiar since it's the same as one of the items in the images
helper module).
Now that our sidebar
module is complete along with its dependent submodules for the various stats, images, and comments, it's time to give our application another test run. Launch the node server and open the application in your browser.
You should now see the sidebar complete with content on both the homepage as well as the image page:
18.221.179.220