Follow me on twitter here.
Subscribe to the sailscasts mailing list here.
The repo for this episode can be found here.
In activityOverlord v1.0 the user interface or
Views of the app were built primarily on the server before being sent to the client and rendered by the client’s browser. This approach is the
V of the MVC architecture and also known as Server Rendering even though the web page is actually being rendered on the client’s browser.
1 2 3 4 5 6
Between the tags is a variable
title. When the Sails server processes this template it will attempt to replace the
title variable with a value, hopefully the page title. This is also called String Interpolation, but I only mention that because I’m a geek.
Server Rendered Views
So let’s review this approach. When a client browser makes a
request to the server, the
router parses the
request and determines where to send it. Now, the resulting
route typically points to a
controller/action that might execute some logic. For example, that logic might include accessing a mongo database that retrieves a stored twitter id and access token. The id and token are then used to request additional details of the user from the Twitter API, all before the server pre-processes a template which contains tags with variables that are replaced by the Twitter details into a
View is then sent back to the client and ultimately rendered by the browser.
Now, this traditional approach to web applications has at least two weaknesses. First, its reliance on the server for page creation means the responsiveness of the app is impeded by the constant round trips necessary to update changes to the
View from the server. Second, is that the API being tightly coupled to the
View makes it less flexible for other potential consumers to use.
A more modern approach to web applications solves both weaknesses by pushing the responsibility for changing the UI to the client as well as decoupling the API to act as an independent provider of endpoints. These endpoints can then be accessed by the browser UI, a native app UI, a mobile UI, or even a smart refrigerator UI.
Now this doesn’t mean that we’ll be abandoning Server Rendered Views entirely. Instead activityOverlordv2.0 will take a hybrid approach using a blend of Server Rendered Views combined with Front-end Framework Components to deliver a UI that makes authentication and SEO manageable. But as usual I’m getting ahead of myself.
So let’s go back to the project and see what Server Rendered Views look like in action. By default, Sails generated three files —
layout.ejs, and a route to the homepage contained in
/config/route.js. So when I make a request in the browser to localhost:1337, the Sails router looks at the request and matches it with the
route in the routes file (e.g.
route.js). This triggers the View Engine to pre-process
homepage.ejs to produce the View that’s being rendered by my browser. The
Layout.ejs file is actually a wrapper around
homepage.ejs. And what I mean by that is if we look at both files you can see that
layout.ejs contains typical mark-up that we want for every page, things like DOCTYPE, html, and head tags. So we have EJS tags here with a
body variable which when processed by the Sails View Engine is replaced with the contents of
homepage.ejs . The result is our View.
Despite it’s power, and to make this example crystal clear, I’m going to disable the layout functionality in Views at least for the time being. To do this I’ll go into into /config/views.js and change the
layout parameter from
layout to false.
The first part of activityOverlord v2.0 consists of the Signup Page and when completed will look something like this. Let’s get started. I’ll first create a new file named
startup.ejs and I’ll put a simple header in it
<h1> Signup Page</h1>. Next, I’ll remove the existing
route to the
homepage and replace it with a
route to the new
The Signup Page:
Let’s take a look. I’ll start Sails using
sails lift and then navigate my browser to
localhost:1337/signup. Okay good, here’s our signup page.
Let’s go back to the
Signup Page and I’ll start by copying in some boilerplate
html. Next, I’ll add our first Angular
directives into the body tag —
ng-cloak. Let’s refresh the browser and see what happens. Well nothing happens, because we haven’t yet added Angular yet. We could manually add the script tags that reference Angular, however, Sails can do this automatically for us using it’s own tagging system (e.g.
<!--SCRIPTS--> tag). You know what, it’s easier just to show you. So I’ll add the tags to
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
I’ll restart the Sails server using
Sails lift and then go back into the browser but also open up the browser console…okay let’s refresh the page and see what happens. Okay, that new, we get this console message that we’re “connected to Sails”, but where did that come from? If we look at the page source we’ll get a clue. Towards the bottom of the page a link to a file named
sails.io.js has been added to our signup page (e.g.
signup.ejs). But where did that link come from? Let’s go into our project in Sublime and navigate to
assets/js. In the dependencies foler there’s our sails.io.js file. First, this file deals with
web sockets and
socket.io, which we’ll be covering in later episodes. The big question now is, how did a link to that file get inserted into
signup.ejs? The short answer is that Grunt did it for us. Okay, so what’s
Of course all of these tasks are happening automatically without us having to be aware of them. However, for those of you who want a little more detail behind the magic, I created a doc that goes into much more specifics of the Grunt/Sails integration than I do in this screencast. The documentation can be found here.
So let’s go ahead and place the main Angular file in the
assets/js folder in Sublime and we’ll create a folder called
public. We’ll put all of our Angular files that have to do with those parts of the application that don’t require authentication. Within
public we’ll create a folder called
signup. And within
signup we’ll create two files SignupModule.js
. Okay, first let's take a look atSignupModule.js` and I’ll add the bare bones Angular code to define our new module.
Next, I’ll open
SignupController.js and add the bare bones Angular code to define our new controller.
Let’s go back to the browser and refresh the page. As you can see, we still have an Angular issue. If we look at the page source, we can see what the issue is,
SignupController is getting loaded before
SignupModule. This is easy to fix and touches on another aspect of Grunt. Most of the configuration for Grunt can be found within the
activityOverlord20/tasks folder. For this issue we’re going to look in the root of the
tasks folder for a file named
pipeline.js. This file contains the configuration for how the SCRIPTS tags are used (e.g.
<!--SCRIPTS-->) as well as some other tags we’ll be using shortly.
Next, I’ll open
pipeline.js in Sublime. We want to load the
1 2 3 4 5 6 7 8 9 10 11
Now when I refresh the browser, Angular no longer complains and if look back at the page source we can see that SignUpModule is being loaded before SignupController.
So let’s go back to signup.ejs in Sublime and insert the remainder of the markup for our Signup Page. Let’s start-up Sails using
Sails lift and navigate the browser to localhost:1337/signup. Although the page loads without errors, there’s some obvious dependencies that need to be added in order for this page to look right. First I’ll add Bootstrap (e.g.
bootstrap.css) to the
signup.ejs. Taking a look at
signup.ejs we can see the Styles tags that were added when I brought in the earlier mark-up as well as a link Grunt automatically created to the bootstrap file I just added.
1 2 3 4 5 6
Next, I’m going to create a
fonts folder and add some fonts we’ll be using later in the interface.
I’m also going to add some
.less files into the
assets/styles folder that we’ll being using later in the interface as well.
You may have noticed the
importer.less file which let’s us control which less files are included the Styles Tag as well as their order. Note that the Grunt task included in Sails will only compile the
.less files that are referenced in this file.
Finally, I’ll add the
CompareTo Angular Directive which will help us with comparing the value of form fields. I’ll place it in the
So let’s see where we are after these dependencies were added. I’ll head back to the browser refresh the page. The console displays an
Uncaught reference error that Angular is not defined. Since this is coming from the
toastr library my hunch is that we have a loading order error. And sure enough if we look at the page source, the
toaster library is being loaded before Angular. I’ll head back to our project and
pipeline.js in sublime and add a reference to Angular here (e.g.
'js/dependencies/angular.1.3.js',) that will load Angular first before any of the other depedencies.
Let’s head back to the browser and refresh the page. Great, there’s no longer and error.
Now let’s take a look at some form validation in signup.ejs. There are three components to the form field validation we’re going to perform. So taking a look at the name field. We first use the ng-class directive to create the
has-error class if the field name is invalid and dirty. This will insert a red border around the input field. Next we’ll configure the validation parameters of the field itself. In this case we’re requiring that the field have a value as well as have a maxlength of 50 characters. Finally, we’ll set-up the text for our error message here.
1 2 3 4 5 6
Let’s see this in action. I’ll go back to the browser and type in a name. Now If I remove the name, the required validation is triggered and if I add to many character’s the maxlength validation will be triggered.
Let’s go back to signup.ejs and review the remaining form fields configuration.
So the Title field’s configuration is identical to the name, the title is required and has a max length of 50 characters.
1 2 3 4 5 6 7 8 9 10 11 12
The Email field is required and requires a properly formatted email address.
1 2 3 4 5 6 7 8 9 10 11 12
The Password field is required and must be at least 6 characters. Also notice that we’re using the CompareTo directive to compare the password field with the confirmPassword model.
1 2 3 4 5 6 7 8 9 10 11 12 13
The Password Confirmation field is required and must match the Password Field.
1 2 3 4 5 6 7 8 9 10
Finally, we disable the form submission button via the
ng-diabled directive until all of the form fields have valid values.
1 2 3 4 5 6 7 8
Okay let’s go back and take a look at the validations in action. I’m going to refresh the browser.
Believe it or not that rounds out our signup page. In the next episode we’ll start to flesh out our initial API that connects the signup page with an endpoint that creates a user account via a model into a database.
You can find all of the source code for this episode at the activityOverlord20 repo on github.
And If have a moment plese follow me on twitter and be sure to signup for the Sailscasts mailing list so I can finally prove to my wife that there are actually folks watching this stuff. As always thanks for watching.