Guiding The Geek In You
Building an AngularJS application using partial views and supported by a Node.js / ExpressJS back-end is doable with a little effort.
Two methods exist for creating modules in AngularJS. I prefer the setter method. Note below we are injecting dependencies on our external controller and ngRoute. Both of these items source from external JS files, so don’t forget to attach them within your index.html.
angular.module('myApp', [ 'ngRoute', 'myApp.controllers' ]).
Pro Tip: Ensure the angular.js version matches angular-route.js! Download them both at the same time from code.angularjs.org.
$locationProvider allows access to .html5mode(), a piece of Angular magic that ensures URLs look like regular URLs in modern browsers, and hash-bangs in older ones. Neat trick! Keep these two caveats in mind when configuring a Node.js / ExpressJS installation:
config(function ($routeProvider, $locationProvider) { $routeProvider. when('/', { templateUrl: 'partials/home', controller: 'HomeController' }). when('/pizza', { template: 'I Love Pizza!' }). otherwise({ redirectTo: '/' }); $locationProvider.html5Mode(true); });
Standard configuration from the Angular perspective thus far. The controller is also super basic – just stubbed out for later use:
angular.module('myApp.controllers', []). controller('HomeController', function ($scope) { });
Configuring Node.js correctly (via the ExpressJS framework) is tricky. However, thanks to btford’s excellent seed project (available on github) I refined this:
var express = require('express'), routes = require('./routes'), http = require('http'), path = require('path'); var app = module.exports = express(); app.engine('html', require('ejs').renderFile); app.set('port', process.env.PORT || 3000); app.set('views', __dirname + '/views'); app.set('view engine', 'html'); app.use(express.logger('dev')); app.use(express.static(path.join(__dirname, 'public'))); app.use(app.router); if (app.get('env') === 'development') { app.use(express.errorHandler()); }
Pro Tip: Make sure this line:
app.use(express.static(path.join(__dirname, 'public')));
comes before this line:
app.use(app.router);
Order matters! We need Node.js to serve the static page request before passing the request to a route handler. This way AngularJS $routeProvider works as it should.
app.get('/', routes.index); app.get('/partials/:name', routes.partials); app.get('*', routes.index);
The code above is the connective tissue between AngularJS and Node.js. First, note the references to routes.index. They point to index.js, the JS file containing the specific routing information about the three potential GETS. The first and third lines will route all traffic to the index page, and line two routes requests to the partials directory (rendering any partials found within). Line three in particular is important, as this catch-all is vital for enabling html5mode in our AngularJS configuration.
Index.js:
exports.index = function(req, res){ res.render('index'); }; exports.partials = function (req, res) { var name = req.params.name; res.render('partials/' + name); };
And finally, to kick off our Node.js server:
http.createServer(app).listen(app.get('port'), function () { console.log('Server listening on port ' + app.get('port')); });
The entire Node.js configuration file:
/********************* * Module dependencies *********************/ var express = require('express'), routes = require('./routes'), http = require('http'), path = require('path'); var app = module.exports = express(); app.engine('html', require('ejs').renderFile); /*************** * Configuration ***************/ // all environments app.set('port', process.env.PORT || 3000); app.set('views', __dirname + '/views'); app.set('view engine', 'html'); app.use(express.logger('dev')); app.use(express.static(path.join(__dirname, 'public'))); app.use(app.router); // development only if (app.get('env') === 'development') { app.use(express.errorHandler()); } /******** * Routes ********/ // serve index and view partials app.get('/', routes.index); app.get('/partials/:name', routes.partials); // redirect all others to the index (HTML5 history) app.get('*', routes.index); /************** * Start Server **************/ http.createServer(app).listen(app.get('port'), function () { console.log('Server listening on port ' + app.get('port')); });
Awesome, an environment which supports AngularJS, runs Node.js / ExpressJS! All that’s missing now is the View.
If you are like me you prefer your HTML as pure as the driven snow. By default Express does not make this possible, as it requires the use of Jade, an HTML Template technology. Fortunately, Embedded JavaScript (ejs) is an easy replacement for Jade, affording us the luxury of a powerful framework and clean markup. Download and install ejs as you would any other node plug-in:
npm install ejs
That’s all folks. Comments, questions? I would love to hear from you. Don’t be shy, and…
Thanks for reading!
Happy New Year! It has been a few weeks since my last post. My sabbatical was refreshing and productive. I finished my first major AngularJS project, which I am excited to start writing about, and of course took some much-needed down time. I hope your end of year festivities were equally pleasant.
This year I have a diverse topic list in store for CompassInHand that I hope will be as interesting to you as it is educational to me. Technology is amazing. There is no end to what can be learned. My hope is that I can give back some of what others are teaching me.
As mentioned, I released my first application written purely in the “Angular way”: Our XBOX 360 Library (OX360L)! If you are interested in checking out the code, please visit the project git repo.
Loyal readers will note: prior to my holiday sabbatical my posting interval was about once per week. Unfortunately I rarely had enough time to do the research, understand the technology, and write a quality post about it within the single week. Therefore my new posting interval will be about twice per month. The additional week will be a tremendous help and should make for tighter posts with more code examples.
While no release date exists yet, this year you can expect CompassInHand to undergo a big face lift. With the help of my good friend (and new father!) Trian Koutoufaris a new WordPress theme is slowly taking shape – including an actual site logo! Stay tuned.
Finally, I plan to begin supporting RSS feeds. This is not a big technical challenge, just an administrative oversight I never considered before. Whether this feature is useful will be up to you guys – please, comment and let me know!
Lots of things!
Over the next several posts I will be discussing some of the many (many, many) lessons I learned while building OX360L. Some of these lesson topics may include:
Looking past Angular / OXB360L, other post topics coming in the next several months will include:
Finally, I have another project getting ready to spin up. Look for hints and mentions as meaningful progress is made. Hopefully it can be useful for all of you who go to lunch with coworkers.
Thanks for reading!
Sometimes the hardest part about a project is sitting down to organize your environment before you begin. Sure, you probably have several, maybe hundreds, of pieces of functional code stashed in your git repo or squirreled away in different folders on your hard drive, but starting a brand new project? Ugh! Enter the project sandbox.
Project sandboxes are templates designed for easy duplication that allow you to quickly create an ideal project environment. Pre-configured folder structures and file names optimized to your liking make launching a new project as easy as duplicating a template and making a tweak to the new project’s server config file.
Similar to regular sandboxes – also known as development servers – project sandboxes isolate projects to a well-defined structure, preventing code pollution. The key difference is Sandboxes are usually designed for developing within an existing code base protected by a code repository. Project sandboxes, however, exist only to help start new and potentially disposable development in a reliable way.
Regarding naming schemes: the word of the day is CONSISTENCY. Name your project sandbox files anything you like and commit to your scheme. When you find a better naming method (and you will), retrofit your project sandbox right away – don’t put it off! Using consistent file names will build strong mental associations that help you decide where to put certain code.
My project sandbox files:
Some file stubs (files that exist without any content) I like keeping handy to handle RWD needs, or to load AMD formatted scripts, respectively:
Flexibility in terms of a project sandbox means keeping a variety of battle tested and carefully vetted resources at your finger tips, not all of which you may need for every project. Some resources should be configured to load by default, while others (like frameworks) are kept out of the loading stack.
Some of my core resources:
General Tools
Asynchronous Resource Loaders
JS MVC Frameworks
JS Libraries
Should you use a CDN or keep your toolkit stored locally? I prefer using local files. Staying local removes a layer of potential complexity (not relying on a file that probably stays the same), improves performance, and keeps resource files readily available for dissection. That said, CDNs are extremely valuable in many other situations.
However, using local resources means you must manually keep your project sandbox current. Get into the habit of watching for updates, reading release notes, and making informed decisions about updating your resources. Broken and dull tools are even worse than no tool at all!
Folder organization depends largely on your web server and middle tier language of choice. Discussing the best ways to organize folders for different servers and languages could be a cool topic for another day.
Since I use Node.js my project sandbox folder structure is pretty simple, as demonstrated below.
Of course, this is only a start! Your project sandbox can be tailored in any way you see fit and will change over time. The important lessons are: make one, keep it consistent, keep it current.
Good luck, and please comment with any suggestions. And as always, thank you for reading!
Special Note: Congratulations to the AngularJS team on their 1.2.0 release! New features, better security, more stability. Read more about it on the AngularJS blog.
Before we continue I would like to quickly mention how important a good sandbox is for the rapid building and breaking of educational code. In an upcoming post I plan to cover how I configure my sandbox. For now I recommend attaching the excellent CSS framework Bootstrap to your project index.html files to take advantage of pre-constructed classes that will make your rendered markup – tables in particular – easier to read.
Note these are View snippets – in order for these Bootstrap classes to work you must initialize the parent containers with their own Bootstrap classes. Again, more on this in a future post.
<div ng-app="myApp"> <div ng-controller="AvengersCtrl"> <table class="table table-striped table-bordered"> <tr ng-repeat="actor in avengers.cast"> <td>{{actor.name}}</td> <td>{{actor.character}}</td> </tr> </table> </div> </div>
Did you notice?
ng-repeat="actor in avengers.cast"
The ng-repeat directive is an example of angular magic; a small directive that drives iterations through data sets without needing extensive pre-configuration. Sweet!
// Initialize App var myApp = angular.module('myApp', []); // Create the Service myApp.factory('Avengers', function() { var Avengers = {}; Avengers.cast = [ { name: "Robert Downey Jr.", character: "Tony Stark / Iron Man" } // rest of the cast added here, more entries = bigger table ]; return Avengers; }); // Define the Controller function AvengersCtrl($scope, Avengers) { $scope.avengers = Avengers; }
Adding a Search filter, for the entire table or for a single column, only requires a small change to the View.
<input type="text" class="form-control" ng-model="search.$">
Using the dollar sign “$” refers to all available fields and is perfect for a table-wide search:
ng-model="search.$"
Replace the dollar sign “$” with “name” to limit searching to the name field:
ng-model="search.name"
Finally, enable search by adding the following:
<tr ng-repeat="actor in avengers.cast | filter:search">
In addition to outputting markup, each ng-repeat loop iteration can also be piped through a filter, as I’ve done in this example. Pattern matching is just one example; many other filters are available for even more advanced output manipulation. Refer to the AngularJS docs for more information on this awesome feature!
Huge credit for my continuing AngularJS education goes directly to egghead.io. Their awesome video library and associated sample code, most of which is FREE, is an incredible addition to the community. Thanks in particular to John Lindquist for explaining these concepts so clearly.
Thanks for reading.
Invented by Trygve Reenskaug, who originally called it the “Thing-Model-View-Editor” way back in 1979 (read all about it), the MVC design pattern has been a staple in software design since it appeared in the Smalltalk-80 class library.
Discussing software design patterns exceeds this post by light years, as does the interior magic of MVC (and siblings such as MVP, and MVVM, and so on). However, let’s cover a couple quick concepts in as non-boring-as-hell way as possible.
The MVC design pattern is focuses on “separation of concerns”. Meaning, software built using this design pattern is composed of pieces belonging to one of three main areas:
For example, when the user interacts with the software by changing the contents of the first name field, the controller handles the user input and changes the state of the model (which is responsible for storing that name somewhere). The controller does not directly tell the view “hey, the user changed the first name and I asked the model to save the information.” Instead the view is observing changes made to the model, and when those changes require a refresh of what the user actually observes on-screen – that refresh happens.
This is simplifying a more in-depth process – but hopefully you can appreciate how each piece has a unique role to play, and that the unity of these roles forms a very tight and reliable pattern for software design.
Absolutely! JavaScript has been in circulation for years. As a language made available via almost every browser it has penetrated into a vast assortment of devices. While the wise programmer will Progressive(ly) Enhance their sites – you never know whether JS is disabled, after all – it’s a safe assumption JavaScript will be available.
Of course raw JavaScript is rarely used anymore in a de-facto sense. While there are obvious speed and precision benefits to hand-coding JS, libraries (and the ocean of plug-ins available there-in) and frameworks take JavaScript development into entirely new realms. Frameworks in particular bring a virtue to the JavaScript ecosystem that have made complex single page development practical.
Understand: when you use a framework your code rests upon and within it. There are rules that should be followed, and coloring outside the lines is discouraged – and can sometimes be disastrous. So choose your coloring book with care.
A quality code base and an appropriate feature list. Will the framework do what you need it to do? Do you understand what’s happening under the hood?
Has the framework been endorsed by big companies? Implementation is a great sign of endorsement – do your research, who’s using this framework?
Are other developers actively supporting the framework? How many? Are the builds coming out fast and furious? Stability is good, commitment to growth over time is even better.
Documentation is vital! A big advantage to a JS MVC framework like Backbone is the sheer number of educational resources available to the developer.
Frameworks exist on an “opinionated” scale. Some, like AngularJS and Ember.js, are tremendously opinionated and will, via convention and scaffolding, handle many basic duties on behalf of the developer. These duties can include standardized file and URL structures. Un-opinionated frameworks like Backbone leave file and URL structuring up to the developer, sometimes frameworks even ask the developer to figure out their own routing and data storage solutions.
How interoperable is this framework? If you want to gently insert pieces of a framework into your existing code base, will the framework tolerate it? Backbone is happily inserted where ever you squeeze it. AngularJS is also friendly, but prefers some control – for example AngularJS prefers (but in no way requires) its built-in jqLite over jQuery, mostly because jqLite makes unit testing easier. Ember.js, however, demands total domination. It wants to control the entire page at run time.
Consider your target audience and the devices they likely use. Now, look at the file size of your framework including all dependencies. Realize that fully featured frameworks like Ember.js come equipped with built in solutions and typically only requires a single dependency, handlebars.js. Backbone, on the other hand, despite how lightweight and un-opinionated it is, needs underscore.js and jQuery (for desktops) and / or zepto.js (for mobile) to run. These requirements add weight.
Finally, avoid the insanity caused by YAFS (Yet Another Framework Syndrome) by downloading and using the amazing TodoMVC. TodoMVC is a collection of many of the leading JS MVC frameworks and assigns a single task to each: render a handy little To-Do List application. The UI is friendly and identical between each implementation. All of the code is exposed and ready for analysis. WooHoo!
Consider the problems solved by a framework:
Now consider the pain a framework implementation will bring:
Lastly, keep in mind that implementing single page applications is the core strength of the JS MVC. Therefore, if your project is a basic web page application a framework might be an over-engineered solution. I say “might” because some frameworks, like Backbone, can usefully solve common issues even in these traditional applications.
Awesome! Go download the framework and the dependencies, then load them into your Hello World project template, just like you would a JS library. Or, if you prefer and the option is available, use the CDN made available by the framework community.
After the World has been Hello’ed adequately, study the TodoMVC implementation of your framework. Peel back the covers, read the comments, study the hell out of the source and do your best to understand what is going on. You may come to rely on the awesome magic Ember.js, AngularJS, or your MVC of choice provides – but first do your best to understand it!
Finally, start your own project. In upcoming posts I will be discussing my project, including which framework I use and why. Stay tuned, and thanks for reading!