sailsCasts

Learning about sails.js one screencast at a time.

Building an Angular Application in Treeline Sneak Peak: Implementing the Signup Page in Treeline.

| Comments

Signup for the Treeline Beta here.

Follow me on twitter here.

Subscribe to the sailscasts mailing list here.

Transcript

Howdy.

So, I wanted to do a quick screencast previewing a new project from the Sails crew called Treeline. So, let’s get busy.

In the last two episodes we implemented the /signup request via Sails blueprints and then a custom controller action. Today, I want to show you how I would do this in Treeline. So I have a Treeline project here, which should look very similar to a Sails project because that’s what it is with some very powerful additions. I’ve copied the assets folder from our existing activityOverlord20 project to the assets folder here. So we have the same front-end asset structure, but I’m going to create the back-end api in treeline.

So here I am in the Main Treeline Dashboard. We’ll go to apps, we’ll create a new app, and not surprisingly we’ll call it activityoverlord20. And the first thing we’re going to do is create our model. Now, in the past episode we created a user mode. We’ll add attributes to that model the first being name and notice that I’m going to add an example, and treeline will infer which type is appropriate. Next, I’ll add the other attributes title, email, password, and gravatar url.

So now that we have our user model let’s define the two routes that our front end requires. The first route will be GET /signup. This takes us into the circuit view. Since we just want to display our signup.ejs view we can specify that in an empty circuit here. Okay, next I’ll create the route to POST /signup. As you may recall we first wanted to take the password from our form and encrypt it. We used node-machines to do that. You can think of treeline as the visual interface for node-machines. So I’ll just drag the encrypt password machine as a part that will fit on something called a circuit. And then I’ll access the password field from our signup page via a route paramter.

Next we want to convert an email address into a gravatar url. I’ll search for the gravatar machinepack and install it. And from with that machinepack I’ll get the getImageUrl machine and put it on our circuit as well. Now similar to what we did with the encrypt password, I need to get our email address from our form and I’ll do that with a route parameter.

At this point we wanted to make sure that we had unique email addresses and if we didn’t to let the front in know via a 409 status code. So I’ll drag a findone user machine over to our circuit and look up the email address provided by our form in the user model. If a record is found, we know the email address is taken and we want to let the front end know so I’ll respond with a 409 status. If a record is not found, we want to go ahead and create the user so I’ll drag a create user machine over and start connecting the user model with our form fields. We’ll do this mainly through route parameters, so for the name we’ll get the route parameter, for the password we’re going to actually get the output of our encrypt password machine. For the email we’ll go ahead and use a route parameter, we’ll do the same for the title field, and finally for the gravatar url we’ll use the output of the gravatar machine.

Okay let’s see all of this in action. So we’ve built the api in Treeline and Treeline syncs the controller and model with our local project when I lift it using Treeline preview. So let’s head to our browser and navigate to localhost:1337/signup which will make the GET request to /signup and our signup view. Next, let’s go ahead and create a User record – Nikola Tesla.

Let’s go back to the signup page and create Nikola Tesla again and see if our duplicate email message is triggered.

And there it is…so this really just scratches the surface of the power of treeline. In addition to the activityoverlord20 screencasts I plan to do additional videos on this new tool. If you’re interested in using treeline, head over to treeline.io and sign up for the beta. As always thanks for watching.

Building an Angular Application in Sails: Ep5 - Creating Custom Actions and an Intro to Node-machines.

| Comments

Follow me on twitter here.

Subscribe to the sailscasts mailing list here.

The repo for this episode can be found here.

Transcript

In the last episode we implemented a request to /signup using a Sails blueprint action. The default blueprint create action is fine but I really don’t want to save passwords in clear text and I also want to generate a gravatar for each user. Let’s overwrite the blueprint create action with our own signup action. This will also let me introduce a new concept to the Sails community — node machines.

So let’s head back to the editor and open up the UserController.js file. I’m going to create an empty signup action here:

1
2
3
4
5
signup: function(req, res){

  return res.ok();

}

Now, let’s navigate your browser to node-machine.org which is kind of the mothership of node-machine information. The first thing to understand is that machines are built on the existing and very powerful node module framework. Second, the node-machine specification and the machines located at nodemachine.org are completely open source and MIT licensed. Third, machines are packaged up in something called a machinepack that can be required just like any other node module from npm. So, I’ll show you how to create node-machines in future screencasts, for now, we’ll be consumers of a couple of them.

I know I want to encrypt passwords so let’s browse the existing machinepacks. So here’s one called passwords. And there’s a machine called encryptPassword that looks kind of interesting. With machines you know exactly what inputs you can use and exactly what you’ll get out from the exits. I’m just going to copy the example usage here and paste it into my signup action. I’ll also move my existing response to the success exit of the machine.

I’m also going to move our response into the success exit. Finally, I’ll grab the password as an input to the machine from a request parameter and if there’s an error I’ll let Sails handle it with res,negotiate and respond with the error. I’m also going to change the default result arguent to a more meaningful name like encrypted password.

So in addition to encrypting the password I want to create a gravatar url from the email address that we get from our user. Let’s go back to node-machine.org and browse to the gravatar machinepack. The getImageUrl machine returns a URL of a gravatar based upon an inputted email address. This machine actually has two ways we can set it up. The example usage is using `execSync(), which allows me to use the machine sychronously. I want to use the machine asynchronously so I'll use.exec()“. Therefore, I’ll also provide both success and error handlers.

So we’ve encrypted our passwords and generated a gravatar URL. Next we’ll save these attributes along with the other fields in our signup form using the create method of our user model. I’ve also added an attribute lastLoggedIn and assigned it the value of the date method. If we get an error I’ll let Sails handle it with res,negotiate and respond with the error. Otherwise I’ll return a response with the id of the new user record as json.

We need to install the two machines we’re using. Open up the terminal window and type npm install machinepack-passwords -save. Next, we’ll install the gravatar machinepack by typing npm install machinepack-gravatar -save.

Okay, let’s make sure all of this works. Restart Sails using sails lift. Again we’re going to get this message about migration. Our choices are: Safe, Drop, and Alter

If I set migrations to safe, sails doesn’t do anything other than create a connection to the database and run queries. It’s the default environment for production and should be used whenever you are working with data you don’t want to risk losing.

Instead of trying to migrate the data in the database this mode drops the database and creates brand new tables, essentially giving you a fresh start. If you have a bootstrap file that resets your data on every lift then the drop migration is a good way to get going when your models are constantly changing in the beginning of a project.

alter is next step up from drop. The difference is that before it drops the database it tries to store all the records in memory and when the table has been re-created it attempts to re-insert them into the new data structure. It’s useful if you have a very small data set and are making trivial changes to the data schema. We’ll ultimately be using safe mode but for now we’ll use alter. We can set this mode by going into the config/models.js file and uncommenting this line.

So let’s lift sails using sails lift. Navigate your browser to localhost:1337/signup. I’ll add another one of my heros Neil Armstrong. And as you can see we have a new record with an encrypted password, a gravatar URL and our lastLoggedIn Attribute.

So far we’ve been using our user model without any attributes. And that’s fine, especially for nosql databases. In this current project, we’re using Sails local disk database that has characteristics of a no-sql database. We’ll be swapping it out for mongo in an upcoming episode. At this point, I want to prevent duplicate users and I also want to prevent the storage of fields other than those I define in my model. This is just a double check because we’re specifying the fields we want to create in our controller action. So we’re currently in the user model via the /models/User.js file. I’m going to add some attributes here. We’re already doing a bunch of validation client side, but since those are not necessarily secure, we’ll reinforce the validation on the back-end. I’ll use the required attribute on some of the fields and the unique attribute on the email field. This will prevent duplicate email addresses from being saved.

So let’s go back to our signup action in the user controller. First I want to parse the error I get back from Sails regarding the duplicate email address. Let’s log the error and take a look at what we get back. So in POSTMAN with Sails lifted. I’ll create the Nikola Tesla record. Now when I try to add Tesla again, I get the unique error. So let’s go back into the action and handle that error. This also let’s me introduce you to custom responses. So if an error exists and it has to do with the email attribute, and the rule that’s being violated is the unique attribute, then I want to respond with this emailAddressInUse function. I’m going to place that function as a custom response in the responses folder. Let’s go ahead and take a look that resonse. So, I’ll get access to the response and then return a more easily parsable object back to the client. So let’s re-lift Sails and in POSTMAN try to add Mr. Tesla again and we get our error object.

Let’s provide for a better user experience to this error on the front end. First we’ll go into the SignUp Module and inject the toastr service we started in the last episode. This will provide us with some great looking messages. Next, we’ll do something similar in the SignupController injecting the toastr service into our controller. So now we need handle the duplicate error response from Sails passing an error message to the user. In the last episode we already set this up in the markup of our signup page. So start Sails and navigate your browser to localhost:1337/signup. I’ll attempt to create Nikola Tesla one more time. And there’s our duplicate user error message, however, the loading state hasn’t changed as evidenced by the animated Create Account button. Okay the reason for this is something most refer to as old age. But the good news it’s an easy fix. So, head back to SignupController and change signupForm.location: false to signupForm.loading: false which is what actually was intended but for you know what. Just to show you it’s fixed I’ll add Nikola again for the last time. And we get both the message and the button with the correct loading state.

Alright, in the next episode we’ll add our login state through a request to /login, our profile page, and a database switch to mongodb. Thanks as always for watching and be sure to follow me on twitter and signup for the Sailscasts mailing list. Also go checkout and signup for the beta of the Sails team’s latest creation Treeline.io.

Building an Angular Application in Sails: Ep4 - Implementing Requests in Angular to a Sails API.

| Comments

Follow me on twitter here.

Subscribe to the sailscasts mailing list here.

The repo for this episode can be found here.

Transcript

Howdy from Austin and welcome back.

It’s now time to get into implementing our Sails back-end api for the signup page. In terms of workflow, we’re going to let the signup page drive the requirements of our Sails back-end. So looking at the signup page I want to find all of the places where the frontend needs to make requests of our backend.

Not to get too nerdy here, but really we’ve already made a request from our browser to our Sails back-end when we loaded the signup page. When I navigated to localhost:1337/signup with the browser, the Sails web server passed our request to the router, which parsed the request, in this case, /signup and matched it with a handler in the routes.js file ultimately responding with this view. So now that we have the signup page rendered in our browser, what other elements in the page need to make requests?

There are at least three different elements that will make requests to the Sails back end api. They include / when the user clicks the activityOverlord2.0 logo, to /login when the user clicks the Sign In button, and to /signup when the user clicks the Create Account button. I’m going to implement the request to /signup first. Now, some of you might be wondering, wait, we’ve already handled a request to /signup. And that’s true but it’s to GET /signup, where GET is the HTTP verb that the browser tpically uses to request web pages. This new request, however, will use the HTTP verb POST as in POST /signup. If this is starting to make your head spin, get your balance and head over to this episode which explains HTTP routing in nauseating detail. Actually I, I hope it isn’t nauseating.

Ok, this POST /signup request will take the gathered contents of this form and send it to the Sails server via an AJAX request from Angular.

So let’s set this up and go b ack in our text editor, wait where’s sublime. I love sublime text but I wanted to experiment with the Atom editor from github for the next serveral episodes….anyway we’re in signup.ejs. And we need to implement this function that the ng-submit directive is pointing to: `submitSignupForm()“. But where do we declare that function? We’ll declare it in our controller which we pointed to via the ng-controller directive here. The actual controller code is contained in a file named SignupController.js by convention because really we could’ve named the fie foo. So here’s where we actually created the controller. So I’ll declare the function here. But this function has no connection or binding to the markup. We’ll use the Angular $scope object to make this connection. Angular characterizes the $scope object as the glue between the controller and directives in the markup. So on the onehand we have controllers contained in javascript files and on the other we have directives contained in mark-up. And the $scope object is used as the bridge between them.

So let’s fire up sails using Sails lift and go into the chrome browser and navigate to localhost:1337/signup. And as you can see here we’ve got an error…our $scope object has not defined. What’s happened is the $scope has not been injected into our function. But we can easily remedy that by passing the scope as an argument into the function. Now when we refresh the browser, we no longer have an issue. But we’re not out of the woods yet.

Angular determines a controller’s dependencies from the arguments to the controller’s constructor function. So if we minify our JavaScript for the Signup controller, all of the function arguments including $scope would be minified as well. So $scope could turn into the letter a and Angular’s dependency injector would not be able to identify services correctly. But there’s an easy fix here. I can add an array to the constructor here that adds a string for $scope and since strings aren’t minified, Angular has a way to match the name with the argument. Let’s go back into browser and refresh and make sure everything works.

Okay great, Next, we’ll enable the loading states we created in the previous episode. I’ll set-up the initial loading state by adding another attribute to the scope object:

1
2
3
4
// set-up loading state
  $scope.signupForm = {
      loading = false;
  }

Now, don’t be confused by my adding the signupForm attribute between the scope object and the loading attribute. I’m just gonna namespace everything concerning the signup form to under this attribute. So when our submitSignupForm() function is executed we want the loading state to change to true. If we look at the markup and specifically the create account button, you can see what’s changing based upon the loading state. If the loading state is false, the button will display the Create Account text. If it’s true, the button will display our spinner animation with the text Preparing your new account within the button. Okay, let’s see if this works. I’ll go back to the signup page and since we have validation I need to put in some valid values and when I click the create account button you can see the loading state change.

So now let’s add the ajax request to our function and we’re going to do that with an Angular service $http. If you’ve ever done an ajax request in jquery, this is going to look very familiar. First, let’s inject it into the function and the array like we did with the $scope object. So we’re going to put in the path and any data we want to send with the request. In order to bind the form fields to these data attributes we’re going to use $scope again. And remember the $scope is linking the values that we’re capturing in the mark-up via the ng-model directive. So let’s do that for the rest of our fields in the form. We’ve got title, and email, and password. Okay great, now let’s declare our success and error handlers. So on success I want to change the location of the browser to /user. This has the effect of making a GET request to /user. If the request generates an error, I want to catch that error and for now just log the response. Finally, I’ll create this catchall function and either way I want to reset the loading state back to false.

We’re now going to transition from the front-end to the back-end. From the angular framework to the Sails framework. Our goal is to create a user by gathering up account information and sending it to Sails. So let’s implement some stuff and then I’ll circle back and explain what we did in more detail.

Head over to the terminal and type sails generate api user. With this simple set of commands and a bunch of tools and automation from Sails, we have almost everything we need for our API. Start the Sails server by typing sails lift.

Because we created a model, Sails is asking us a question about migrations, we’ll come back to this. For now I’m going to use the second option — alter.

Next, let’s go into the browser and navigate to localhost:1337/user. We’ve just used one of Sails blueprint shortcut actions. By navigating to ‘/user’ we made a GET request to the server for all the user records. And since we haven’t created any records yet, not suprisingly we get an empty array. But using the create action blueprint shortcut I’ll create our first user record — Humphrey Bogart. Sails also has blueprint rest or RESTful actions. From within POSTMAN, really one of the best tool on the planet for testing routes, I’ll make a POST request to /user with these route parameters for our next user Aimee Mann. Chances are you’ll create your own Controller Actions by the time you get to production. However, Blueprints are incredibly useful in the design phase of your API. If you interested in learning more about Blueprint capabilities, head over to this episode where I break them down in a bunch of detail.

So the path we want to associate with create a user is /signup. So head back into the editor and open up \config\routes.js. I’m going to add the route POST /signup which will be handled by the UserController.create action. Let’s restart Sails and navigate to the signup page. Finally, I’ll signup my hero Nikola Tesla. And there’s our list of records.

So briefly I want to go over what we’ve done. We created a route that connects the request to a controller and action. When the api was created, Sails provided us with a user controller and a create action (via blueprints) automatically. Sails also created a user model that has model methods like .create, .find, .update, and .destroy. Finally, the user model can retrieve and save records from a variety of databases via adapters.

In the next episode we’ll transition from Sails blueprints to our custom action. I’ll also introduce a brand new Sails concept — node machines. Thanks as always for watching and be sure to follow me on twitter and signup for the Sailscasts mailing list. Also go checkout and signup for the beta of the Sails team’s latest creation Treeline.io.

Building an Angular Application in Sails: Ep3 - Understanding Asset Delivery Options in Our SignUp Page.

| Comments

Follow me on twitter here.

Subscribe to the sailscasts mailing list here.

The repo for this episode can be found here.

Transcript

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.

This so called Server Rendering is the server preprocessing one or more templates of markup, usually some combination of HTML, CSS, and Javascript and combining them with data via a Template Engine. All template engines use some form of tags that surround variables that when processed yield a result. Sails uses the EJS template engine by default. For example, this template contains some standard HTML mark-up along with EJS tags.

1
2
3
4
5
6
<!DOCTYPE html>
<html>
  <head>
    <title><%- title %></title>
  </head>
  ...

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. The 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 — homepage.ejs, 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 layout.ejs with 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:

1
'GET /signup': {view: 'signup'}

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-app, ng-controller, and 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 signup.ejs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html>
  <head>
    <title>Sign Up for Activity Overlord (angular)</title>

    <!-- Viewport mobile tag for sensible mobile support -->
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

  </head>

  <body ng-app="SignupModule" ng-controller="SignupController" ng-cloak>
    <h1>The Signup Page
    <!--SCRIPTS-->
    <!--SCRIPTS END-->
  </body>
</html>

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 namedsails.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 Grunt?

Grunt calls itself a JavaScript Task Runner but really Grunt is all about automation. It allows you to create repetive tasks that can be executed automatically. For example, there’s a Grunt task that’s looking for changes in the Sails assets folder. Sails creates a .tmp folder in the root of our project. As we can see here any files in the assets folder are copied into .tmp/public which acts like a static file folder you’d find on any web server. But what about the link to sails.io.js? This is yet another Grunt Task that will place a link to any javascript file found in assets/js that has the corresponding Script tags we just placed in signup.ejs (e.g. <!--SCRIPTS--><!--SCRIPTS END-->).

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/dependencies folder and I’ll refresh the browser. Looking at the page source we can see that a link to angular has been automatically placed in our signup page. But when I refreshed the browser, Angular is mad at us because we have some directives in the signup page without any associated javascript files. But not to worry, we can easily fix that. Let’s navigate back to 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.jsandSignupController.js. Okay, first let's take a look atSignupModule.js` and I’ll add the bare bones Angular code to define our new module.

1
angular.module('SignupModule', []);

Next, I’ll open SignupController.js and add the bare bones Angular code to define our new controller.

1
angular.module('SignupModule').controller('SignupController', function(){});

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 SignupModule after dependencies but before any other javascript files. So we’ll put the path to our file here.

1
2
3
4
5
6
7
8
9
10
11
...

  // Dependencies like jQuery, or Angular are brought in here
  'js/dependencies/**/*.js',

  // All of the rest of your client-side js files
  // will be injected here in no particular order.
  'js/public/signup/SignupModule.js',
  'js/**/*.js'

...

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 /assets/sytles folder. Similar to what we did with javascript files in the previous episode, Sails will automatically include links to the CSS in 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
...

    <!--SCRIPTS-->
    <!--SCRIPTS END-->
  </body>
</html>

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.

I’m also be adding Jesús Rodríguez’s https://github.com/Foxandxss fantastic angular messaging library Angular-toastr. The library contains both a javascript and a css 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 /js/dependencies folder.

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
<!-- Also, if signup.name.$dirty is true, show the message depending upon the particular properties truthiness (e.g. required
and/or maxlength) -->
<span class="help-block has-error" ng-if="signup.name.$dirty">
  <span ng-show="signup.name.$error.required">Name is required.</span>
  <span ng-show="signup.name.$error.maxlength">The name cannot be more than 50 characters.</span>
</span>

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
<!-- T I T L E -->

<div class="control-group form-group col-md-12"
  ng-class="{'has-error':signup.title.$invalid &&
                        signup.title.$dirty}">
  <label>Your title</label>
  <input type="text" class="form-control" placeholder="e.g. Genius" name="title" ng-model="signupForm.title" ng-maxlength="50" required>
  <span class="help-block has-error" ng-if="signup.title.$dirty">
    <span ng-show="signup.title.$error.required">Title is required.</span>
    <span ng-show="signup.title.$error.maxlength">The name cannot be more than 50 characters.</span>
  </span>
</div>

The Email field is required and requires a properly formatted email address.

1
2
3
4
5
6
7
8
9
10
11
12
<!-- E M A I L -->

<div class="control-group form-group col-md-12"
ng-class="{'has-error':signup.email.$invalid &&
                      signup.email.$dirty}">
  <label>Your email address</label>
  <input type="email" class="form-control" placeholder="nikola@tesla.com" name="email" ng-model="signupForm.email" required >
  <span class="help-block has-error" ng-if="signup.email.$dirty">
    <span ng-show="signup.email.$error.required">Email address is required.</span>
    <span ng-show="signup.email.$error.email">Not a valid email address.</span>
  </span>
</div>

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
<!-- P A S S W O R D -->

<div class="control-group form-group col-md-6"
ng-class="{'has-error':signup.password.$invalid &&
                      signup.password.$dirty}">
  <label>Choose a password</label>
  <!-- Added the compareTo directive that compares the passowrds -->
  <input type="password" class="form-control" placeholder="at least 6 characters" name="password" ng-model="signupForm.password" id="password" required ng-minlength="6" compare-to="signupForm.confirmPassword" >
  <span class="help-block has-error" ng-if="signup.password.$dirty">
    <span ng-show="signup.password.$error.required">Password is required.</span>
    <span ng-show="signup.password.$error.minlength">Password must be at least 6 characters.</span>
  </span>
</div>

The Password Confirmation field is required and must match the Password Field.

1
2
3
4
5
6
7
8
9
10
<!-- C O N F I R M  P A S S W O R D -->

<div class="control-group form-group col-md-6">
  <label>Re-enter your password</label>
  <input type="password" class="form-control" placeholder="one more time" name="confirmation" ng-model="signupForm.confirmPassword" required>
  <span class="help-block has-error" ng-if="signup.confirmation.$dirty">
    <span ng-show="signup.password.$error.compareTo">Password must match.</span>
    <span ng-show="signup.confirmation.$error.required">Confirmation password is required.</span>
  </span>
</div>

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
<!-- C O N F I R M  P A S S W O R D -->

<!-- Disable signup button until the form has no errors -->
<button class="btn btn-primary btn-lg btn-block" type="submit" ng-disabled="signup.$invalid">
  <span ng-show="!signupForm.loading">Create Account</span>
  <span class="overlord-loading-spinner fa fa-spinner" ng-show="signupForm.loading" ></span>
  <span ng-show="signupForm.loading">Preparing your new account...</span>
</button>

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.

Setting Up the Development Environment and Creating Your First Project

| Comments

Follow me on twitter here.

Subscribe to the sailscasts mailing list here.

Transcript

Howdy and welcome back.

As in the previous series, I’m going to assume you already have Node installed. If you don’t there’s a bunch of helpful documentation on nodejs.org and installers for both Mac OS X and Microsoft Windows can be found here as well as binaries for Linux and SunOS.

As for as my development enviornment, I’m using OS X v10.10.1 also known as Yosemite. For my text editor I’m using Sublime Text 2 which can be found here. There’s also an update to the editor, version 3, which I’m not currently using but can be found here. Another tool we’ll be using is the quite awesome chrome extension, known as – POSTMAN which can be found here.

And last but certainly not least I’ll be using Sails v0.11.0. Now, you may see me running some release candidates of Sails initially, however, because the release of Sails v0.11.0 is eminent, I’m not going to bother with how to install a release candidate and these initial screencasts are really not effected by the currently published version of v0.10.5. Okay let’s get Sails up and running by heading over to the terminal window.

From the last series, I received comments from a bunch of folks who had a real aversion to the terminal window. For those of you who are new to back-end programming, jumping into the terminal window might seem intimidating. Let me start by saying if I can understand it, believe me you can understand it. By the end of this series you’ll wonder how you got through your day without multiple visits to the terminal. For those of you on OS X you’ll find the terminal application is somewhat hidden in /Applications/Utilities/Terminal.app. One other potential point of confusion about the terminal is how it’s referred to. For example you’ll hear terminal window, prompt, command-line, shell, etc. For what it’s worth here is my attempt at terminology superimposed on this thing I’ll be calling the terminal.

With that said, let’s jump in.

To install sails, you simply type npm install sails -g, where the -g stands for global. Note, that because of the way ownership rights are set up on my machine, I have to use sudo or super duper user, actually according to wikipedia it means substitute user do….something like that. Regardless, it allows you to temporarily issue a command as a super or root user. After that Sails will start installing, so see ya in second.

So, in the last series of building activity overlord some people were confused about the distinction between installing sails globally and where Sails is installed when creating a new project. By installing Sails globally, we can have access to command-line tools from anywhere on the command-line.

For example, let’s create the initial Sails project for activityOverlord v2.0. From the terminal I’ll type sails new activityoverlord20.

So what just happened? Sails used the globally installed version of itself to generate all of the necessary initial structure for our application. This includes installing a copy of Sails itself inside the root of our application. That way, sails applications are completely self contained…there’s no “other software” outside of our project that we’re dependent upon.

Throughout these screencasts there will be times that I want to address specific changes that effect the previous activityoverlord screencasts with v0.11.0 of Sails. So if you don’t have previous experience or interest with older versions of Sails, now is the time to pick up that musical instrument or check some texts for the next few seconds. When I created the new Sails project you may have noticed that I didn’t use the --linker prarameter. That’s because there’s no longer a requirement to use it. By default, that functionality is built into every Sails project.

Now, let’s go back to the terminal and move into the new project by typing cd acitivtyoverlord20. Without changing any of the initial files or folders of the app I can start our newly created web server by typing sails lift and Sails confirms that it is indeed up and running. Next, I’ll open a browser at localhost:1337. The browser is accessing the default home page Sails generated when we initially built the project.

It’s important to take a moment here and realize what we’ve just accomplished. In just a few commands we’ve built the initial infrastructure of a web application which includes the creation of its own web server. We then have a browser, known as the client that is making a request for a previously generated home page through the Sails web server. The Sails server then response with the home page to be rendered in the browser.

Some of you may be confused by the address localhost:1337. Typically, when you browse the web you’ll enter a domain name like google.com…and that name actually resolves to an some ip address which maps to some computer out on the internt. Alright, localhost is default name for what is technically termed a loopback address. My machine’s localhost points to the address 127.0.0.1. What the loopback address allows allows us to do is bypass the outside network and address a specific web service on our local machine. In our case that web service is the Sails server. So when the Sails starts or lifts, by default, it’s given a port number of 1337. As we’ll see in a second we can change the port number if we want. Port numbers are the way in which we can differentiate one web service from another. For example, I currently have our activityoverlord20 project running on port 1337. I created another Sails project called foo that I’m going to lift on port 1338. When I go into the browser and open the address localhost:1338 the homepage that I altered comes up for the foo project. So the combination of localhost and the port number allows us to run both the server and client on the same machine while we’re building the project. To get completely geeky, and show you that localhost is really an arbitrary, there’s a file found on my mac at ~/etc/host that specifies what “points” to 127.0.0.1. As you can see, in addition to localhost I have the name yaya also pointing to 127.0.0.1 and yes we can go into the browser and type yaya:1337 and our homepage comes up.

Okay, I think I’ve beat that one to a pulp…but sometimes you know I just get carried away. In the next episode we’ll start building up the client ui of activityOverlord v2.0. So, see ya’ll in a bit.