Rendering with Node.js - Node.js for .NET Developers (2015)

Node.js for .NET Developers (2015)

Chapter 4. Rendering with Node.js

Now that we’ve covered routing and the basic sending of a response to a web request, let’s start bringing your Node.js application into the real world. In this chapter, you’ll add some real webpages that allow users to interact with a data-driven UI.

Before you start

You have a couple more npm packages to hook up before you can get going. I realize this tutorial is falling into a pattern where I say, “Let’s get going!” only to have you turn the page and discover there’s just a wee bit more setup to do before you can actually get going. Sorry about that! Again, all I can do is remind you that this is Node.js Land where, unlike the Microsoft “add-a-page-and-then-a-control-and-click-go model,” nothing comes built-in. Before you can implement anything even as simple as a single webpage for a website, you need to have a plan in mind and then set the actual tools in place. Every project you do for Node.js will be same—built from the ground up. You can come up with your list of chosen tools and try to be as efficient as you can putting them in place (such as installing everything you think you might need when you first begin, as we did). In the end, though, you will still need to assemble the parts in your application.

One of the npm packages you installed when you first set up your environment was EJS, or Embedded JavaScript. This component will serve as your rendering engine. You need to do a few things to enable your application to use EJS.

First, in your app.js file, add this line:

server.set('view engine', 'ejs');

This statement can go either above or below the line where you set the path to your views.

Now to associate the files you want to render with the EJS engine, you have to change the file extension of your HTML files from .htm (or .html) to .ejs.

As long as the file name of your .ejs file is the same as the name of your .js “View_Model” file (in our case, both are called survey) and you added the page as a static reference in the file that begins your Node.js application (which you did by adding the path with a combination of the usefunction and the require function in your app.js file), you are all set to start rendering the page. Again, if you already have Model-View-Controller (MVC) development experience, you can skim over a lot of this tutorial because it is similar to the MVC patterns you have seen in the past. However, as I already mentioned, I won’t assume you have such experience and I’ll walk you through the process step by step.

Inside your get function, change the send to a render and specify the intended view (in this case survey):

router.get('/survey', function (req, res) {
res.render('survey');
});

For the moment, just put some dummy HTML content inside of the body tag of your survey.ejs view, like this:

<i>Hello World</i>

Then browse to http://127.0.0.1:1234/survey as you did earlier. You will see your page content say hello to you, displayed in italics.

To see the effect, now change

res.render('survey');

to

res.render('survey2');

Then browse to the same page as you did earlier. Node.js will throw an error. It isn’t exactly a “404 Page Not Found” error, but it’s very close. In your browser window, it should say

Cannot get 'survey'

This specific error message is telling you one of two things. You might have a name mismatch in your code (meaning that nowhere in a relevant .js file is there a function called get that takes the exact path ‘/survey’ or whatever exact pattern came in the URL request). Or the error message is telling you that your server isn’t running. (Depending on your version of Microsoft Visual Studio or Node.js, you might get a “file not found” or “failure to lookup” error, but it doesn’t matter. The point is that it doesn’t work.)

These two files, the .ejs file and the .js file of the same name, work in concert in the same way that your code-behind page supports the ASPX file containing your HTML tags. The actual syntax of the .ejs files, however, will be reminiscent of old ASP or current MVC/Razor. Sadly, the beautiful and elegant object-oriented control you have with Web Forms that truly was a great leap forward for web programming over a dozen years ago is nowhere else to be found except in the land of .NET.

By the way, forgive an old .NET evangelist for saying this, but if you think what I just said is an overstatement, it isn’t in the least. To have anywhere close to the same level of command over HTML controls in a stateless web page from code-behind that you have over a Windows Form is a mind-blowing concept still to this day. And still, in an awful lot places all over the planet, a screen flicker for a postback—that in most cases could be AJAX with the same underlying OOP platform—is a small price to pay for the speed and power of that kind of software development.

At the time .NET came into being around the turn of the century, new programming platforms were coming out every six months. In fact, if you want to know what it was like back then, we have the proof with us still to this day. Microsoft didn’t even realize what it had when it released ASP.NET. Why do you think something that codes like ASP.NET—specifically, an OOP pattern (when done properly) that has nothing to do with how you build webpages in ASP—has a name so misleading it leads you to think it is similar? The answer is that, at the time, Microsoft was worried that people would be hesitant to embrace yet another new technology, so the company smudged one name into the other. Well, 15 years later, Web Forms is still here and still everywhere.

My point is only that Node.js is just another way of doing things. Some parts will be better, and some parts not so much. In some ways and in some cases, it might be superior to ASP.NET, but that fact doesn’t make Web Forms anything but a rock-solid technology that has lasted for a decade. In lots of ways, for lots of businesses and clients, the extra work for building even a simple user interface that Node.js demands will not be cost effective. This whole skill set just offers you and your company new options for building solutions.

If you enjoy MVC development, this extra effort will all be no problem for you and you will be quite used to the demands and the patterns. But if you are coming from happy-go-lucky OOP Land, where you drag-and-drop from a toolbox and magically have all control properties at your fingertips to do with as you will, getting used to doing things this way will take some time. (And if you used to do ASP way back when and joyfully thought spaghetti code went away with the Y2K scare, well, the “new web” is just rife with it all over again. Node.js is as good a place as any to get back into it!)

This style of coding is known as using a template. Consider the two following chucks of code for a list of products:

var html = "<h1>"+data.title+"</h1>"
html += "<ul>"
for(var i=0; i<data.products.length; i++) {
html += "<li><a href='products/" + data.products[i] + "'>"

html += data.products[i] + "</a></li>"
}
html += "</ul>"

Versus this:

<h1><%= title %></h1>
<ul>
<% for(var i=0; i<products.length; i++) { %>
<li>
<a href='products/<%= products[i] %>'>
<%= products[i] %>
</a>
</li>
<% } %>
</ul>

These look similar, but they are different in a couple of key ways.

The first example is pure JavaScript. The line you need to add to render this list as written simply assigns the resulting HTML string to a div, a literal, or whatever control suits you. If beyond this you want to style the results, for example, you need to incorporate all of that into your JavaScript code. So it can quickly grow to be very complex, when all you really wanted to do was present a recordset to a user.

The second example is a template. The HTML tags are fixed and provide the presentation structure into which the code contained in the <% %> brackets will populate the data. As I mentioned, for anyone who has done ASP or MVC, all of this will look familiar. You will also notice that the JavaScript data object does not exist and has been replaced by this <%= %> syntax, which EJS recognizes as a property/variable value that it should fetch from the matching .js file of the same name.

This is where any similarity to code-behind ends. JavaScript knows nothing about properties, references, and so on. If you want your page to process some data when it renders, you have to explicitly supply that data when you tell the page to display. So, for the preceding example, you supply the products array during the get function when the request comes in:

res.render('products', {
products: the ArrayYouBuild
});

Then you also supply the title and any other arguments needed for EJS. Make sure they are comma delimited for each argument provided:

res.render('products', {
products: the ArrayYouBuild,

title: "My Products"

});

Title, for example, is used here:

<h1><%= title %></h1>

Now, assuming you had some data in the ArrayYouBuild, the page renders your products along with the title of the list.

Using real data

Let’s begin using our real data, even if we won’t render it quite this way in the final version. To start with, you’ll show a simple list of players that will ultimately become one of your sets of answers for multiple-choice questions.

First, prepare the .ejs file. It will be similar to the template example shown earlier. Drop this code into your survey.ejs file:

<ul>
<% for(var i=0; i< players.length; i++) { %>
<li>
<a href= 'details/<%= players[i].id%>'>
<%= players[i].name%>
</a>
</li>
<% } %>
</ul>

As you can see, it’s just a for loop expecting to fill an unordered list with an array of some kind. So let’s provide one. In your survey.js file, create the following array:

var thePlayers = [
{ id: 0, name: 'Walter Payton', sport: 'Football'},
{ id: 1, name: 'Babe Ruth', sport: 'Baseball' },
{ id: 2, name: 'Wayne Gretzky', sport: 'Hockey' },
{ id: 3, name: 'Tiger Woods', sport: 'Golf' },
{ id: 4, name: 'Bobby Orr', sport: 'Hockey' }
];

This is the raw data for the array.

Change your rendering code as follows in your get function:

res.render('survey', {
players: thePlayers
});

Now if you browse to the survey page as before, you should see your list of players with the name displayed. If you mouse over the name, you should see a link in your status window with the player ID appended in the URL. It navigates to a page you have not yet constructed, so if you click the link, you will receive a “Cannot GET details” response.

So you successfully connected your .js and .ejs files to display a page containing data you built from arguments you supplied during the routing. With this major step behind you, go back and clean up what you did to make it all object-oriented as I discussed.

Convert this raw array data from JSON to OOJS format:

var thePlayers = [
{ id: 1, name: 'Walter Payton', sport: 'Football' },
{ id: 2, name: 'Babe Ruth', sport: 'Baseball' },
{ id: 3, name: 'Wayne Gretzky', sport: 'Hockey' },
{ id: 4, name: 'Tiger Woods', sport: 'Golf' },
{ id: 5, name: 'Bobby Orr', sport: 'Hockey' }
];

Here is that JSON in OOJS using properties of the Person and Player objects created earlier:

function Person(){
this.id = 0;
this.lastName = "";
this.firstName = "";
}
function Player () {
this.prototype = Person;
this.sport = "";
this.displayName = function(){
return (this.lastName + ',' + this.firstName);
}
}

The preceding code sets up your basic Person object and then prototypes your Player object to it. Now you declare your array and some players to put into the array:

var arrPlayers = [];
var oPlayer = new Player();
oPlayer.firstName = "Walter";
oPlayer.lastName = "Payton";
oPlayer.sport = "Football";
oPlayer.id = 1;
arrPlayers.push(oPlayer);
var oPlayer = new Player();
oPlayer.firstName = "Bobby";
oPlayer.lastName = "Orr";
oPlayer.sport = "Hockey";
oPlayer.id = 5;
arrPlayers.push(oPlayer);
var oPlayer = new Player();
oPlayer.firstName = "Wayne";
oPlayer.lastName = "Gretzky";
oPlayer.sport = "Hockey";
oPlayer.id = 3;
arrPlayers.push(oPlayer);
var oPlayer = new Player();
oPlayer.firstName = "Babe";
oPlayer.lastName = "Ruth";
oPlayer.sport = "Baseball";
oPlayer.id = 2;
arrPlayers.push(oPlayer);
var oPlayer = new Player();
oPlayer.firstName = "Tiger";
oPlayer.lastName = "Woods";
oPlayer.sport = "Golf";
oPlayer.id = 4;
arrPlayers.push(oPlayer);

Now just change your code to pull the new array, like this:

res.render('survey', {
players: arrPlayers
});

When you run your page again, you should see the same output as you did earlier except with the names now shown as Last, First.

You have now rendered a page using Node.js and object-oriented JavaScript. Obviously, there is more to do with the integration of the survey question structure, but you have the basic elements and concepts in place. Before we dig into them any more deeply, let’s take a quick look at adding a few simple features to the page, such as images and styling.

Adding images and styling

Images are simple. Drop them in your page with a tag to the correct path for the image:

<img src="img1.jpg" alt="img1" />

Grab an image from somewhere, call it img1, and browse to the page. You’ll see it appear.

For styling, I preloaded an npm package called Bootstrap, which I managed to install by using Bower. We’ll dig much more into Bootstrap later, but for the moment let’s just hook it up and let it work some quick magic for us.

Bootstrap is a massive collection of CSS classes that provide you with insta-styling by simply hooking the class into whatever tag you have by using the class attribute. Even something as simple as our unordered list can get a two-second facial upgrade by just referencing Bootstrap as you would a typical .css file.

In this case, you just have to find it first. Look under

bower_components\bootstrap\dist\css

and you’ll see

bootstrap.css

So just add a link to it in the usual way to the <head> section of your .ejs page:

<link href="bower_components/bootstrap/dist/css/bootstrap.css" rel="stylesheet"
type="text/css" />

Then just wrap your starting .ejs code in an HTML table that has a bootstrap .css table class reference, like this:

<table class="table">
<tr>
<td class="center">
<ul>
<% for(var i=0; i< players.length; i++) { %>
<li>
<a href= 'details/<%= players[i].id%>'>
<%= players[i].displayName()%>
</a>
</li>
<% } %>
</ul>
</td>
</tr>
</table>

Now when you browse to the survey page, you’ll see a much improved overall appearance. Just like that.

Granted it isn’t much to start with, but then again you had to do very little so far. As I mentioned, I’ll cover a few more Bootstrap features later on, but it’s definitely the kind of library you want to play with to see the effects. Just as an example, drop this attribute inside your image tag:

<src="img1.jpg" alt="img1" class="img-rounded" />

You’ll begin to get a feeling for what I mean about Bootstrap. Play with it, and you’ll find it can snazzy-up a webpage in some very professional ways with not much effort. Reference the right .css class within the library and you’re pretty much done.

So you’ve coded your server and constructed your first basic get route. You’ve had the correct page rendered with data, images, and styling. And you’ve used object-oriented JavaScript in combination with Node.js. Your basic tools are in your toolkit. Now we’ll bring the application into the real world of software by connecting to external data sources, allowing for user interaction, and providing login security.