HTML5 Zone is brought to you in partnership with:

I delight in stories, systems, and people. If you are one of these things, you delight me. Developer advocate at Cloudant by day, high probability I'm sleeping by night. Do what you love, and let your works speak for you. Developer evangelist at Cloudant. Max is a DZone MVB and is not an employee of DZone and has posted 3 posts at DZone. You can read more from them at their website. View Full User Profile

Chaise Blog: building a diary with Angular.js, Grunt.js and Cloudant

07.30.2013
| 3153 views |
  • submit to reddit

 

Angular.js is a client-side JavaScript framework by Google that makes writing sophisticated, interactive Web apps super easy. It makes previously complicated tasks nearly effortless, without the boilerplate Backbone tends to carry. Combined with Cloudant, you can build some really neat stuff right quick.

Grunt.js is a task-runner for JavaScript projects. Like a Makefile, it lets you automate building, installing, and updating projects. Combined with its tremendous ecosystem of plugins, you can automate preparing assets for production, testing your application, and pushing it live -- and that’s just for starters.

In this post, I’ll talk about how I used Angular.js, Grunt.js, and Cloudant to build...

Chaise Blog

Chaise Blog!

For those thoughts you want to reflect on alone, I wrote Chaise Blog. You can click around a demo of it here. In essence, it's less a blog and more a diary; I figured I'd leave authentication and the like for a later iteration. Basic features:

  • Web interface for reading, submitting, and editing posts.

  • Designate posts as drafts to hold them separately from published material.

  • While editing posts, Chaise autosaves them every few seconds.

  • Write posts in Markdown; HTML preview generated as you write.

  • URL rewrites let you use shorter URLS like chaisedemo.maxthayer.org

Putting that together took a couple hours. It was shockingly easy. Here’s how:

  • In addition to raw JSON data, Cloudant can store files and serve them up. So, for simple applications, Cloudant can serve as my datastore and web server. I used this architecture because of Chaise’s minimal needs, and the ease of deploying this way. I still recommend putting a server between your client and your datastore for most projects.

  • Angular.js gets post data from Cloudant and renders it into HTML templates.

  • Grunt.js automates concatenating and minifying static assets like CSS and JavaScript, and then pushing the whole mess into Cloudant. This means deploying Chaise takes one command: grunt.

Angular.js

Egghead.io has a superb set of Angular.js screencasts. Rather than try to re-invent the wheel and write my own tutorial, I highly recommend you check out those videos if you're getting started with Angular.

Angular shines in teaching stateless design. Your application's controllers, templates, utilities, and middleware are encapsulated from one another, such that re-using parts, nesting them, and sharing data between them, becomes effortless.

app.js

The shortened contents of Chaise’s app.js, which drives the whole application. The full file clocks in at only 138 lines!

I used services and factories to share data and functions between my controllers, such as with app.factory(‘getPosts’, function(...){...}) establishing how to get diary posts from the server, which then gets reused by both PostsCtrl and DraftsCtrl. To expose Markdown rendering to the template, app.filter(‘markdown’, function(md){...}) uses the md service from the top of the file to create a markdown filter which our templates can use. To that effect, check out what templates look like in Angular.js:

Angular templates are just HTML

That’s the entire file. That template isn’t inside a <script type="text/template”> tag. It’s straight HTML, marked up with attributes that Angular uses to do its magic. For example, ng-repeat yields the template once for each element in the posts array, which our controllers attach to the template’s scope. {{ post.date | date:’MM/dd/yyyy’ }} renders each post’s date according to the given date format.

Chaise instructs the router to haul in this template, posts.html, which then gets used by both PostsCtrl and DraftsCtrl without either controller knowing anything about the template. They just attach data to the scope object the template and controller share. This detachment makes code re-use super easy.

This gorgeous slidedeck explains more about using $provides directives to structure your application's parts, which gave me that "I can see forever" moment of clarity, and approximately halved how much code I needed to write.

C'mon grab your friends

"Oh my Glob!" Jake shouted, “I can see forever! It’s all dependency injection and decoupled data structures!”

Plus Cloudant

Normally, when building a new web app, I'd need to build an API layer between my database and any application consuming it. Except, Cloudant provides that API layer without limiting my choices for backend technologies.

By default, Cloudant databases can only be accessed by the account owner, so only you can see and use your Chaise -- just like a diary :D For the Chaise demo, I just made the database publicly readable (one click on the Permissions tab) and presto, demo.

My favorite part of the Angular code employing Cloudant is how unspecial it is. No dependencies. No external libraries. No integrations. Just straight HTTP calls. For example, here's that autosave feature:

// autosave posts while writing them
// requires:
//  - $http: make HTTP requests
//  - $timeout: wrapper around setTimeout
//  - root: root URL for our database
app.factory('autosave', function($http, $timeout, root){
  return function(post){
    (function _autosave(){
      $http({
        url: [root, post._id].join('/')
      , method: 'PUT'
      , data: post
      })
      .success(function(data, status){
        post._rev = data.rev;
        $timeout(_autosave, 5000);
      })
      .error(function(){
        console.log(arguments);
      })
      ;
    })();
  };
});

Given a post object, every five seconds, it calls itself and PUTs the current version of the document to the server, updating the rev field with the returned value. Angular handles keeping the post object in sync with what the user is modifying.

Grunt.js

In its first iteration, Chaise used a crude Makefile to automate the build process. Then I learned about Grunt.js, and, as if waking from a depression, the world filled with color.

Grunt.js is a task runner for JavaScript projects, whether that means a backend server using Node.js or a front-end project built on client code alone. Its tremendous ecosystem of plugins (and the effortlessness of writing your own) allowed me to automate not only pushing Chaise into the wild wild web, but also linting, concatenating, and minifying assets. Here’s what it looks like:

Chaise's Gruntfile

Registers pre-installed tasks, plus one I wrote in that get_imgs file we require, then register default which runs them all in turn. When you run grunt from command line, it runs the default task unless you specify otherwise.

If you have Grunt and Node.js on your machine then getting, building, and pushing Chaise live is four commands:

git clone git@github.com:garbados/chaiseblog.git
cd chaiseblog
npm install
grunt

Congratulations, my friend: your Chaise Blog is now live.

Published at DZone with permission of Max Thayer, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)