About this book

JavaScriptMVC is a client-side, JavaScript framework that builds maintainable, error-free, lightweight applications as quickly as possible. As it does not depend on server components, it can be combined with any web service interface and server-side language.

"Learning JavaScriptMVC" will guide you through all the framework aspects and show you how to build small- to mid-size well-structured and documented client-side applications you will love to work on.

This book starts from JavaScriptMVC installation and all its components are explained with practical examples. It finishes with an example of building a web application. You will learn what the JavaScriptMVC framework is, how to install it, and how to use it efficiently.

This book will guide you on how to build a sample application from scratch, test its codebase using unit testing, as well as test the whole application using functional testing, document it, and deploy the same. After reading Learning JavaScriptMVC you will learn how to install the framework and create a well-structured, documented and maintainable client-side application.

Publication date:
May 2013
Publisher
Packt
Pages
124
ISBN
9781782160205

 

Chapter 1. Getting Started with JavaScriptMVC

In this chapter, get an overview of the JavaScriptMVC framework. We will install it, go through the architecture, and learn it in the best possible way. Finally, we will build a simple application. There is nothing that works better than an example. Some say this is the only thing that works.

 

What is JavaScriptMVC?


JavaScriptMVC (JMVC) is a JavaScript open source model-view-controller (MVC) framework build, on top of the jQuery library.

It is the backend agnostic client-side framework that can be used with any backend solution, such as Node.js, Ruby on Rails, Django, and so on.

The idea behind JavaScriptMVC is to provide a set of tools to build high quality and maintainable applications in the shortest amount of time possible.

JavaScriptMVC contains the following independent components:

  • StealJS: This is the dependency manager and production build

  • FuncUnit: This is the unit and functional test component

  • jQueryMX: This contains a set of plugins that provide the functionality to implement and organize large JavaScript codebases into a well-structured and organized form, provide a model-view-controller abstraction layer

  • DocumentJS: This is the documentation

The first version was published in May 2008. Current Version 3.2 was released in December 2010. The latest version at the time of writing this book is 3.2.2.

In the next Version 3.3 of JavaScriptMVC, which should be released soon, jQueryMX project will be replaced by CanJS. Projects using current version of JMVC should work after small refactoring with JMVC 3.3 thanks to the names fallback.

JavaScriptMVC 4.0 will be renamed to DoneJS and contain significant changes to StealJS which will be fully AMD compatible work with CommonJS and run with Node.js. FuncUnit will be split into 3 parts: Syn - Synthetic event library, ShouldJS - Asynchronous test driving using Jasmine or QUnit and DidJS - Automated test runner bindings for Jasmine or QUnit for Selenium, PhantomJS, and so on.

License

JavaScriptMVC is licensed under the MIT license with the following exceptions:

  • Rhino: This is the JavaScript command line (MPL 1.1)

  • Selenium browser automation (Apache 2)

Links

You can refer to the following URLs to learn more about JavaScriptMVC:

 

Why JavaScriptMVC?


JavaScriptMVC is a solid and well documented framework.

It is based on the extremely popular JavaScript library jQuery, where many JavaScript programmers are familiar with its factory methods and chainable function style.

JavaScriptMVC is a complete package. It contains everything we need to build, manage, document, and test JavaScript projects.

Since it is a modular framework, we don't need to use all the available components. We can start by using only framework components that we actually need, and add additional components as and when we need them.

The learning curve is pretty low, especially if a reader is familiar with other JavaScript frameworks, such as lightweight Backbone and Sammy or heavyweight toolkits such as Dojo toolkit or Google Closure. At the same time, it offers much more than lightweight brothers without a heavy feel, such as Google Closure which produces much cleaner code and provides better documentation than the very popular Dojo toolkit.

One of its killer features is that it prevents memory leakage. This is a very important aspect of client-side applications, which perform many operations on the Document Object Model (DOM) tree.

Tip

MVC in JavaScriptVC

JavaScriptMVC utilizes the classic MVC pattern, which separates business logic and application data from the user interface.

 

System architecture approach


When building web applications, we can distinguish between two approaches—multi-page application and single-page application.

In multi-page application, most of the business logic is implemented in the backend system, with some enhancement done in JavaScript. For example, the Ruby on Rails application, where most of the main logic is done by the backend MVC architecture and when a user navigates to another page, an ordinary http request is sent.

In single-page application, most of the business logic is implemented on the frontend side. For example, the JavaScriptMVC application, where most of the main logic is done by frontend MVC architecture. When a user navigates to another page, the frontend router dispatches all requests and makes calls to the back end API written; for example, in Sinatra.

JavaScriptMVC single-page application

JavaScriptMVC is designed for single-page application use cases. It's good to know about the advantages and disadvantages of the single-page application approach compared to that of the multi-page application.

Advantages

  • Most of the states are maintained in the client, so we don't need to keep the session states on the server side

  • Most of the requests are done through XRH calls, so there is no need to load a new page each time, which could cause high memory footprint (especially in the old fashion, non event-based servers such as Apache)

  • Most of the business logic is on the client side, so we can save many calls to the server

Downsides

  • Load balance and Content Delivery Network (CDN) can be tricky since RPC is used to move data back and forth between the server and client.

  • Search Engine Optimization (SEO) can be tricky due to on-demand JavaScript built pages.

 

Real-world examples


Readers can find web applications built with the JavaScriptMVC framework at http://community.javascriptmvc.com/posts/in-bucket/apps.

 

Installing JavaScriptMVC


Installing JavaScriptMVC is as easy as making tea, but faster.

Choosing your method

There are three methods.

The last two methods are the preferred way, for the following reasons:

The third method seems to be the best one, because it contains all the advantages from the second one, plus it creates an encapsulated environment, which we can easily and quickly create or delete without affecting our current development environment setup.

Which method is right for me?

For a fast tryout library, choose the first method. For the actual development, definitely choose the second one.

The first method – download the package

In this method, we will use a web interface on the JavaScriptMVC web page to configure and download the package:

  1. Download the complete package from http://javascriptmvc.com and unpack its content.

  2. Create a folder named Todo under the local web server working directory.

  3. Copy all files from javascriptmvc-3.2.2 to the Todo folder and start the web server.

    $ mkdir Todo && cp -r javascriptmvc-3.2.2/* Todo && cd Todo
    

That is it; we are all set and ready to go.

The second method – pull the code from Git repositories

We assume that the reader knows and has installed Git.

If not, the following resources might be helpful:

In the following steps, we are going to install JavaScriptMVC for our Todo example project:

  1. Under local web server directory, create new folder named Todo:

    $ mkdir Todo && cd Todo
  2. Inside the Todo folder, create a new Git repository:

    $ git init
  3. Add JavaScriptMVC components as submodules to the project:

    $ git submodule add git://github.com/bitovi/steal.git
    $ git submodule add git://github.com/bitovi/documentjs.git
    $ git submodule add git://github.com/bitovi/funcunit.git
    $ git submodule add git://github.com/jupiterjs/jquerymx jquery
  4. Install and update the submodules:

    $ git submodule init
    $ git submodule update
  5. The last module we need to install is Syn. Since it is already a submodule to the FuncUnit project, all we need to do is initialize and update it:

    $ cd funcunit
    $ git submodule init
    $ git submodule update
  6. Switch Syn to the master branch:

    $ cd syn/
    $ git checkout master
  7. Go back to the root directory of the project:

    $ cd ../..
  8. Move the js command to the root directory of the project:

    $ ./steal/js steal/make.js
Verifying Installation

The project directory should have following folder structure:

.git
.gitmodules
documentjs
funcunit
jquery
js
js.bat
steal

That is it; we are all set and ready to go.

Note

More about submodules in Git: http://git-scm.com/book/en/Git-Tools-Submodules

The third method – Vagrant

To install JavaScriptMVC using this method, we need to install Vagrant, which is a virtualized development tool wrapper around Oracle VM VirtualBox, an x86 and AMD64/Intel64 virtualization software package.

  1. Download and install Oracle VM VirtualBox (https://www.virtualbox.org).

  2. Download and install Vagrant (http://downloads.vagrantup.com).

  3. Download an unpack the JavaScriptMVC kick-starter (https://github.com/wbednarski/JavaScriptMVC_kick-starter/archive/master.zip).

  4. Inside JavaScriptMVC kick-starter folder type vagrant up.

    This command creates a virtual environment and a projects directory. It also installs the web server. JavaScriptMVC framework will be placed in the Todo directory.

Any changes we make inside the projects directory are immediately visible in web browser at http://192.168.111.111/.

 

Documentation and API


Good documentation and API, many tutorials, and a well documented codebase is the strong side of JavaScriptMVC:

Active community on the forum and Stack Overflow:

 

The architecture of JavaScriptMVC


The architecture of JavaScriptMVC is modular. The powerful stack contains everything we need to build a well organized, tested, and documented application.

Here is a list of the JavaScriptMVC key components as well as topics covered in the next chapters.

DocumentJS

DocumentJS is an independent JavaScript documentation application and provides the following:

  • Inline demos with source code and HTML panels

  • Adds tags to the documentation

  • Adds documentation as favorite

  • Auto suggest search

  • Test result page

  • Comments

  • Extends the JSDoc syntax

  • Adds undocumented code because it understands JavaScript

FuncUnit

FuncUnit is an independent web testing framework and provides the following:

  • Test clicking, typing, moving mouse cursor, and drag-and-drop utility

  • Follows users between pages

  • Multi browser and operating system support

  • Continuous integration solution

  • Writes and debugs tests in the web browser

  • Chainable API that parallels jQuery

jQueryMX

jQueryMX is the MVC part of JavaScriptMVC and provides the following:

  • Encourages logically separated, deterministic code

  • MVC layer

  • Uniform client-side template interface (supports jq-tmpl, EJS, JAML, Micro, and Mustache)

  • Ajax fixtures

  • Useful DOM utilities

  • Language helpers

  • JSON utilities

  • Class system

  • Custom events

StealJS

StealJS is an independent code manager and build tool and provides the following powerful features:

Dependency management

  • Loads JavaScript and CoffeeScript

  • Loads CSS, Less, and Sass files

  • Loads client-side templates such as TODO

  • Loasd individual files only once

  • Loads files from a different domain

Concatenation and compression

  • Google Closure compressor

  • Makes multi-page build

  • Pre processes TODO

  • Can conditionally remove specified code from the production build

  • Builds standalone jQuery plugins

Logger

  • Logs messages in a development mode

Code generator

  • Generates an application skeleton

  • Adds the possibility to create your own generator

Package management

  • Downloads and install plugins from SVN and Git repositories

  • Installs the dependencies

  • Runs install scripts

  • Loads individual files only once

  • Loads files from a different domain

Code cleaner

  • Runs JavaScript beautifier against your codebase

  • Runs JSLint against your codebase

 

Building simple applications


We installed JavaScriptMVC and went briefly through its components. Now, we are ready to build our first JavaScriptMVC application.

Excited? Let's do the magic.

Todo list

We are going to learn JavaScriptMVC on the classic example application – the to-do list.

Note

If you are curious and want to compare different JavaScript frameworks based on the todos application examples, then the GitHub project is absolutely fantastic. You can find it at https://github.com/tastejs/todomvc/tree/gh-pages/architecture-examples. The project home page is at http://todomvc.com/.

Loader

In the Todo folder that we created during installing JavaScriptMVC, create a folder named todo. Create files named todo.html and todo.js inside todo.

The project directory should have following structure:

Todo/
    .git
    .gitmodules
    todo/
        todo.html
        todo.js
    documentjs
    funcunit
    jquery
    js
    js.bat
    steal

Copy and paste the following code into todo.html to load the StealJS and todo.js files:

<!doctype html>

<html>
    <head>
        <title>Todo List</title>
        <meta charset="UTF-8" />
    </head>
    <body>
        <ul id="todos">
            <li>all done!</li>
        </ul>

        <script src="../steal/steal.js?todo"></script>
    </body>
</html>

Note

../steal/steal.js?todo is the equivalent of ../steal/steal.js?todo/todo.js. If file name is not provided StealJS, try to load the JavaScript file with the same name as the given folder.

In todo.js, add the following code to load the jQueryMX plugins. They are necessary to implement this application:

steal(
    'jquery/class',
    'jquery/model',
    'jquery/dom/fixture',
    'jquery/view/ejs',
    'jquery/controller',
    'jquery/controller/route',
    
    function ($) {

    }
);

Open the page in a web browser by typing http://YOUR_LOCAL_WEB_SERVER/Todo/todo.html, and use a web development tool, such as Google Chrome Inspector, to check if StealJS and all the listed plugins are loaded properly.

Model

The next step is to add a model to our application by extending $.Model from the jQueryMX project.

The first parameter is the model name (string), the second parameter is the object with the class properties and methods. The last parameter is the prototype instance property, which we leave as an empty object for this example:

steal(
    'jquery/class',
    'jquery/model',
    'jquery/dom/fixture',
    'jquery/view/ejs',
    'jquery/controller',
    'jquery/controller/route',

    function ($) {
        $.Model('Todo', {
                findAll: 'GET /todos',
                findOne: 'GET /todos/{id}',
                create:  'POST /todos',
                update:  'PUT /todos/{id}',
                destroy: 'DELETE /todos/{id}'
            },
            {

            }
        );
    }
);

Note

Class properties are not random; they are described in the model API. http://javascriptmvc.com/docs.html#!jquerymx.

We've created the Todo model for our todo list application. Now, it's time to play around with it.

  1. Open a web browser and type the following line into the JavaScript console:

    var todo = new Todo({name: 'write a book'});

    todo is now an instance of Todo with property name and property value write a book.

  2. Get the property value as follows:

    todo.attr('name');
  3. Set the property value if the property exists, as follows:

    todo.attr('name', 'write JavaScript book');

    Or by attrs, where we can set more then one property at the time as well as add a new property:

    todo.attrs({name: 'write JavaScriptMVC book!'});
  4. Add two new properties:

    todo.attrs({
        person: 'Wojtek',
        dueDate: '1 December 1012'
    });
  5. List all the properties:

    Todo.attrs();

The following screenshot shows the execution of the preceding commands:

Fixtures

Since we have no backend service to handle /todo API calls in our frontend application, any attempt to invoke one of the model's CRUD methods on the Todo model will cause a network error.

Note

Create, Read, Update, Delete (CRUD) are the four basic functions of persistent storage.

At this point, $ .fixture comes to the rescue. With this feature, we can work on a project even when backend code is not ready yet.

Create fixtures for the Todo model:

steal(
    'jquery/class',
    'jquery/model',
    'jquery/util/fixture',
    'jquery/view/ejs',
    'jquery/controller',
    'jquery/controller/route',

    function ($) {
        $.Model('Todo', {
                findAll: 'GET /todos',
                findOne: 'GET /todos/{id}',
                create:  'POST /todos',
                update:  'PUT /todos/{id}',
                destroy: 'DELETE /todos/{id}'
            },
            {

            }
        );

        // Fixtures
        (function () {

            var TODOS = [
                // list of todos
                {
                    id:   1,
                    name: 'read The Good Parts'
                },
                {
                    id:   2,
                    name: 'read Pro Git'
                },
                {
                    id:   3,
                    name: 'read Programming Ruby'
                }
            ];

            // findAll
            $.fixture('GET /todos', function () {
                return [TODOS];
            });

            // findOne
            $.fixture('GET /todos/{id}', function (orig) {
                return TODOS[(+orig.data.id) - 1];
            });

            // create
            var id = 4;
            $.fixture('POST /todos', function () {
                return {
                    id: (id++)
                };
            });

            // update
            $.fixture('PUT /todos/{id}', function () {
                return {};
            });

            // destroy
            $.fixture('DELETE /todos/{id}', function () {
                return {};
            });

        }());
    }
);

Now, we can use our Todo model methods as if backend services were here.

For instance, we can list all todos:

Todo.findAll({}, function(todos) {
    console.log('todos: ', todos);
});

The following screenshot shows the output of the console.log('todos: ', todos); command:

View

Now, it is a good time to add some HTML code to actually see something beyond the browser console. To do this, use the open source client-side template system Embedded JavaScript (EJS).

Create a new file todos.ejs in the todo directory (the same folder where todo.js is located), and add the following code to it:

<% $.each(this, function(i, todo) { %>

    <li <%= ($el) -> $el.model(todo) %>>
        <strong><%= todo.name %></strong>
        <em class="destroy">delete</em>
    </li>

<% }) %>

Then, type the following in the console:

$('#todos').html('todos.ejs', Todo.findAll());

Now, we can see all todos printed:

Basically, the EJS template is an HTML file with injected JavaScript code between <% and %> or <%= and %> (and a few other ways).

The difference is that in the second case, all the values returned by the JavaScript code are escaped and printed out. In the first one, they are only evaluated.

The first line is a jQuery each loop— no magic here. However, the next line could be a new thing for many readers. It is ECMAScript Harmony-like, arrow style syntax for functions used by the EJS parser that doesn't darken the whole picture by its simplicity.

The following syntax:

($el) -> $el.model(todo)

Can be explained as follows:

function ($el) {
    return $el.model(todo)
}

Controller

Let's add some action to our user interface.

Add the following code to the todo.js file, and refresh the application in a browser:

$.Controller('Todos', {
    // init method is called when new instance is created
    'init': function (element, options) {
        this.element.html('todos.ejs', Todo.findAll());
    },

    // add event listener to strong element on click
    'li strong click': function (el, e) {
        // trigger custom event
        el.trigger('selected', el.closest('li').model());

        // log current model to the console
        console.log('li strong click', el.closest('.todo').model());
    },

    // add event listener to em element on click
    'li .destroy click': function (el, e) {
        // call destroy on the model to prevent memory leaking
        el.closest('.todo').model().destroy();
    },

    // add event listener to Todo model on destroyed
    '{Todo} destroyed': function (Todo, e, destroyedTodo) {
        // remove element from the DOM tree
        destroyedTodo.elements(this.element).remove();

        console.log('destroyed: ', destroyedTodo);
    }
});

// create new controller instance
new Todos('#todos');

Now, you can click on the todo name to see the console log or delete it.

The init method is called when a new controller is instantiated.

When the controller element is removed from the DOM tree (in our case, #todos), the destroy method is called automatically, unbinding all controller event handlers and releasing its element to prevent memory leakage.

Routing

Replace the following code:

// create new Todo controller instance
new Todos('#todos');

With:

// routing
$.Controller('Routing', {
    init: function () {
        new Todos('#todos');
    },

    // the index page
    'route': function () {
        console.log('default route');
    },

    // handle URL witch hash
    ':id route': function (data) {
        Todo.findOne(data, $.proxy(function (todo) {
            // increase font size for current todo item
            todo.elements(this.element).animate({fontSize: '125%'}, 750);
        }, this));
    },

    // add event listener on selected
    '.todo selected':  function (el, e, todo) {
        // pass todo id as a parameter to the router
        $.route.attr('id', todo.id);
    }
});

// create new Routing controller instance
new Routing(document.body);

Refresh the application and try to click on the todo list elements. You will see that the URL updates after clicking on the todo item with its corresponding ID.

Complete application code

Here is the complete code for the Todo application:

steal(
    'jquery/class',
    'jquery/model',
    'jquery/util/fixture',
    'jquery/view/ejs',
    'jquery/controller',
    'jquery/controller/route',

    function ($) {
        $.Model('Todo', {
                findAll: 'GET /todos',
                findOne: 'GET /todos/{id}',
                create:  'POST /todos',
                update:  'PUT /todos/{id}',
                destroy: 'DELETE /todos/{id}'
            },
            {

            }
        );

        // Fixtures
        (function () {
            var TODOS = [
                // list of todos
                {
                    id:   1,
                    name: 'read The Good Parts'
                },
                {
                    id:   2,
                    name: 'read Pro Git'
                },
                {
                    id:   3,
                    name: 'read Programming Ruby'
                }
            ];

            // findAll
            $.fixture('GET /todos', function () {
                return [TODOS];
            });

            // findOne
            $.fixture('GET /todos/{id}', function (orig) {
                return TODOS[(+orig.data.id) - 1];
            });

            // create
            var id = 4;
            $.fixture('POST /todos', function () {
                return {
                    id: (id++)
                };
            });

            // update
            $.fixture('PUT /todos/{id}', function () {
                return {};
            });

            // destroy
            $.fixture('DELETE /todos/{id}', function () {
                return {};
            });
        }());

        $.Controller('Todos', {
            // init method is called when new instance is created
            'init': function (element, options) {
                this.element.html('todos.ejs', Todo.findAll());
            },

            // add event listener to strong element on click
            'li strong click': function (el, e) {
                // trigger custom event
                el.trigger('selected', el.closest('li').model());

                // log current model to the console
                console.log('li strong click', el.closest('.todo').model());
            },

            // add event listener to em element on click
            'li .destroy click': function (el, e) {
                // call destroy on the model to prevent memory leaking
                el.closest('.todo').model().destroy();
            },

            // add event listener to Todo model on destroyed
            '{Todo} destroyed': function (Todo, e, destroyedTodo) {
                // remove element from the DOM tree
                destroyedTodo.elements(this.element).remove();

                console.log('destroyed: ', destroyedTodo);
            }
        });

        // routing
        $.Controller('Routing', {
            init: function () {
                new Todos('#todos');
            },

            // the index page
            'route': function () {
                console.log('default route');
            },

            // handle URL witch hash
            ':id route': function (data) {
                Todo.findOne(data, $.proxy(function (todo) {
                    // increase font size for current todo item
                    todo.elements(this.element).animate({fontSize: '125%'}, 750);
                }, this));
            },

            // add event listener on selected
            '.todo selected':  function (el, e, todo) {
                // pass todo id as a parameter to the router
                $.route.attr('id', todo.id);
            }
        });

        // create new Routing controller instance
        new Routing(document.body);
    }
);
 

Summary


In this chapter, we learned what JavaScriptMVC is, and why it is a good and solid framework. We also learned how to install it, and browse the documentation and API. We got an overview of its architecture by building a simple application.

If you can understand all the code that we have written in this chapter, you will be able to dig into the framework easily and fast. Congratulations!

About the Author

  • Wojciech Bednarski

    Wojciech Bednarski is a software engineer with expert knowledge of client-side technologies. He is passionate about JavaScript, Node.js, HTML5, Ruby, NoSQL, and POSIX-compliant systems.

    While at university he started taking up freelance jobs and was obsessed by web accessibility and usability as well as web standards.

    Then, he moved to Warsaw where he started working as a web developer at eo Networks, which is recognized as one of the 50th fastest growing company in Central Europe.

    He then started work at Roche, one of the largest pharmaceutical companies in the world, where he worked on large scale web-based systems as well as conducted workshops and technical seminars. He was recognized with an Informatics Service Award in the category of Innovation.

    He then moved to Copenhagen and started work at YouSee, the subsidiary of TDC, the biggest Danish telecom company, where he programmed set top boxes. He won Copenhagen Startup Weekend and also began the Everplaces startup.

    At the time of writing this book, he is a consultant for a New York-based company working on the next big thing you will use. He works from different places and lives with his beautiful wife and two black cats. He also loves taking pictures, you can have a sneak peek at www.pixmod.net. He is also fond of driving sports cars and traveling.

    You can visit his professional profile at www.linkedin.com/in/bednarski/ or you can follow him on Twitter @wbednarski.

    Browse publications by this author
Book Title
Access this book and the full library for FREE
Access now