CanJS

javascript-mvc

Articles
Resources
Related Libraries and Tools
Plugins

can.Model
can.View
can.Stache
can.Mustache
can.EmbeddedJS

can.Construct
can.Observe
can.Control
can.Component
can.List
can.Map
can.compute
can.Deferreds
can.route

can.event
Event Handling
Live Binding
Utility functions

How to build a contact list
Place My Order
Todo application
Twitter Bootstrap tabs with canjs Control and Routing
Chat
Model Queue
Recipes
Other examples

Miscellaneous
Questions

What is CanJS?

CanJS is a lightweight front-end JavaScript MVVM framework that helps developer structure and organize their application.

Why should I use CanJS?

  1. CanJS aims to be the best of both world (light weight versus heavy weight). It is supposed to be:
    • Easy to learn
    • Small in size
    • Basic MVC
    • Flexible / Extensible
    • Live binding (two-way binding)
    • RESTful models
    • Custom tags
    • Observables
    • Computed Properties
    • Memory Safety
    • Responsive widgets
    • Reuse existing templates
    • Work with different libraries
    • Two-way data binding
  2. It is the MVC component extracted from JavascriptMVC
  3. It is backed by Bitovi, a company that does consulting. It is not a big company compared to Google or Yahoo, but it is a commercial company nonetheless.

How can we download CanJS?

Go to http://canjs.com/ and click on the download button.

Can we customize what get downloaded?

Yes. Go to http://canjs.com/ and click on the customize button next to the download button.

How can we download CanJS using Bower?

bower install canjs --save
bower install canjs#1.1.8 --save // install a specific version of CanJS

How can we load CanJS?

After you download CanJS, unzip the zip file. The full download contains:

  1. can.<library>.js (e.g. can.jquery.js) - The core build for a supported library
  2. can.<library>.min.js - The minified core build for a supported library
  3. can.<library>.dev.js - A development build logging useful messages for a supported library
  4. can.<type>.<plugin> - Individual builds for each official CanJS plugin
  5. amd/ - CanJS provided as AMD modules (see [using-require using with RequireJS] for usage)
  6. amd-dev/ - CanJS AMD modules with development messages
  7. steal/ - CanJS modules using the StealJS syntax (see [using-steal using with StealJS])

If you wish to use CanJS with jQuery, first load your jQuery library and then load CanJS with:

<script src="http://canjs.com/release/latest/can.jquery.js"></script>

How can we load CanJS using AMD / RequireJS?

The default library used with AMD modules is jQuery. CanJS will reference the jquery module so that name needs to point to your jQuery source and the can module name needs to be mapped to the amd/ folder of the CanJS download. In RequireJS a simple configuration looks like this:

<script type="text/javascript" src="require.js"></script>
<script type="text/javascript">
      require.config({
        paths : {
          "jquery" : "http://code.jquery.com/jquery-2.0.3",
          "can": "path/to/can/amd"
        }
      });
      require(['can/control', 'can/view/mustache'], function(Control, can) {
        // Use Mustache and Control
        var MyControl = Control.extend({
          init: function() {
            this.element.html(can.view('path/to/view.mustache', this.options));
          }
        });
      });
</script>

The can module is a shortcut that loads CanJS's core plugins and returns the can namespace:

require(['can'], function(can) {
      // Use can.Control, can.view, can.Model etc.
});

If you would like to use another library, map the can/util/library module to can/util/zepto, can/util/yui or can/util/mootools. With RequireJS and Zepto, it loks like this:

require.config({
      paths : {
        "can": "path/to/can/amd",
        "zepto" : "http://cdnjs.cloudflare.com/ajax/libs/zepto/1.0rc1/zepto.min"
      },
      map : {
        '*' : {
          "can/util/library" : "can/util/zepto"
        }
      }
});
bower init
bower install jquery requirejs canjs --save

And initialize RequireJS on our HTML page and point the root module to js/app:

<script data-main="js/app" src="bower_components/requirejs/require.js"></script>

In js/app.js:

require.config({
    paths : {
        "jquery" : "bower_components/jquery/jquery",
        "can": "bower_components/can/amd"
    }
});

require('./my-control', function(MyControl, can) {
    new MyControl('body', {});
});

In js/my-control.js:

require(['can/control', 'can/view/mustache'], function(Control, can) {
    // Use Mustache and Control
    return Control.extend({
        init: function() {
            this.element.html(can.view('views/index.mustache', {
                message: 'CanJS'
            }));
        }
    });
});

In view/index.mustache:

<h1>Hello {{message}}!</h1>

You are set up and good to go. Follow up in the Using CanJS in production section on how to pre-compile your views and make a build using the RequireJS optimizer.

CanJS can pre-compile EJS and Mustache views into JavaScript functions contained within a single file in order to avoid additional requests for view files in production.

npm install can-compile -g

And in your project root folder run:

can-compile --out views.production.js

This will create views.production.js in the current folder containing all pre-compiled views. When loaded into your page CanJS will use the per-compiled views instead of making an Ajax request to retrieve them.

You can run the RequireJS optimizer against your application but need to make sure to put all the configuration in a separate file, e.g. js/app.js:

require.config({
    paths : {
        "jquery" : "http://code.jquery.com/jquery-2.0.3",
        "can": "path/to/can/amd"
    }
});

require(['can/control', 'can/view/mustache'], function(Control, can) {
    // Use Mustache and Control
    var MyControl = Control.extend({
        init: function() {
            this.element.html(can.view('path/to/view.mustache', this.options));
        }
    });
});

Then run r.js like:

r.js js/app.js

To use your pre-compile views with RequireJS just add a custom wrapper in the options that uses the AMD definition to load can/view/mustache and/or can/view/ejs (depending on what you are using). In a Grunt task:

module.exports = function (grunt) {
  // Project configuration.
  grunt.initConfig({
    options: {
      wrapper: 'define(["can", "can/view/stache"], function(can) { {{{content}}} });'
    },
    cancompile: {
      dist: {
        src: ['**/*.stache', '!node_modules/**/*.stache'],
        dest: 'production/views.production.js',
      }
    }
  });
}

To load the generated files only when running the RequireJS optimizer r.js define an empty module in development like:

define('views', function() {});

And require('views'); in your main application file. When running the optimizer map this module to the production build file:

paths: {
  views: 'views.production'
}

Always make sure that the output file is in the same folder as the root level for the views that are being loaded. So if your CanJS applications HTML file is in the app folder within the current directory use a filename within that folder as the output file:

can-compile --out app/views.production.js --can 2.0.0

How can we scaffold a CanJS application using Yeoman?

npm install -g yo bower grunt generator-canjs

// Create the main application folder, go inside the main application folder,
// and generate the rest of the application's folder structures
mkdir canjs-app && cd canjs-app
yo canjs

// Install or add various dependencies
bower install -S bootstrap fontawesome

// Scaffold the user model.  
// Creates the user.js file in the models folder.
// Model generator will offer to create fixtures for the generated model. 
// The User model fixtures will be generated in the fixtures/users.js file.
yo canjs:model models/user

// Scaffold the user control.
// The canjs:control generator is different from the canjs:model generator.
// It doesn't create just one file. Instead, it creates a folder which contains
// all files needed to run this control in isolation.
yo canjs:control controls/users

// Watch for changes in files (in one terminal window)
grunt watch

// Start the server
grunt connect:server

// Compile JavaScript and view files to the production.js file
grunt build

The canjs:control generator is different from the canjs:model generator. It doesn't create just one file. Instead, it creates a folder which contains all files needed to run this control in isolation. If you run it like:

yo canjs:control controls/users

it will create following structure:

controls/
  users/
    users.js // control file
    users.html // demo page
    init.mustache // example mustache view
    init.ejs // example ejs view

When you ran the app generator the style folder was created. Usually I use the style/style.less as the starting point for my CSS styles. First, let's set up Bootstrap and FontAwesome. Create the variables.less file in the style folder and copy the contents from the bower_components/bootstrap/less/variables.less in to that file.

Copy contents from the bower_components/bootstrap/less/bootstrap.less to style/style.less and adjust the paths for all the files except the variables.less file (we're loading that one from the style folder). Your style/style.less file should look something like this:

// Core variables and mixins
@import "variables.less";
@import "../bower_components/bootstrap/less/mixins.less";

// Reset
@import "../bower_components/bootstrap/less/normalize.less";
@import "../bower_components/bootstrap/less/print.less";

// Core CSS
@import "../bower_components/bootstrap/less/scaffolding.less";
...
@import "../bower_components/bootstrap/less/responsive-utilities.less";

Bootstraping Bootstrap (yeah, I know :)) from the style/style.less file allows us to make changes to the styles in the isolation from the original Bootstrap code. This makes future upgrades of the Bootstrap library painless and simple.

App generator created two .html files in the project root. The canjs-app.html file and the production.html file. canjs-app.html file will be used for the development, as it loads the dev versions of all scripts, while the production.html loads only the built file.

We set up the base app structure, and now is the time to add support for the components. When developing CanJS apps, it is a good practice to develop each component in the complete isolation from the rest of the app. All of it's styles, templates and assets should be contained in one folder, ready for reusing. There is a problem with supporting the image and font paths in the CSS. We want our CSS to work the same in three different contexts:

  1. Component development mode (loaded from: localhost://9001/components/some_component/some_component.html)
  2. App development mode (loaded from: localhost://9001/components/app.html)
  3. App production mode (loaded from: localhost://9001/components/production.html)

App development and production mode are pretty much the same, but we have an issue with the component development mode since it will load the CSS from the different location. Thankfully, LESS compiler can rewrite urls in the build step, so we can get the correct urls in the built CSS. To take advantage of this, I recommend you to use the following technique:

  1. Create style/components.less file and @import each component's LESS file from there
  2. Import style/components.less file from the style/style.less file
  3. Load the built 'style/style.css' file from the component's demo page (eg. components/users/users.html) as it will have the correct paths
yo canjs:component components/users
[?] Please enter the path to the component eg.: components/users: components/users
create components/users/users.js
create components/users/users.html
create components/users/users.less
create components/users/users.mustache
identical components/users/users.less

How can we scaffold a CanJS plugin using Yeoman?

A CanJS application is different from a CanJS plugin.

How can we pre-compile our templates?

See the canjs-steal page.

How can we use CanJS with Bower or Grunt?

bower init
bower install jquery canjs --save

And the following index.html in the same folder, that also loads the Pushstate and can.Map.backup plugins:

<html>
    <head>
        <title>CanJS Tutorial</title>
    </head>
    <body>
        <script src="bower_components/jquery/dist/jquery.js"></script>
        <script src="bower_components/canjs/can.jquery.js"></script>
        <script src="bower_components/canjs/can.route.pushstate.js"></script>
        <script src="bower_components/canjs/can.map.backup"></script>
        <script src="js/app.js"></script>
    </body>
</html>

In js/app.js:

$(function() {
    // Your CanJS code here
});

An easy way to get this setup production ready is creating an index.production.html that references the production files:

<html>
    <head>
        <title>CanJS Tutorial</title>
    </head>
    <body>
        <script src="production.js"></script>
    </body>
</html>

With Grunt as a build tool your Gruntfile.js to create production.js can look like this:

    module.exports = function(grunt) {
      grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        concat: {
          options: {
            separator: ';'
          },
          dist: {
            src: [
              'js/**/*.js',
              'bower_components/jquery/dist/jquery.js',
              'bower_components/canjs/can.jquery.js',
              'bower_components/canjs/can.route.pushstate.js',
              'bower_components/canjs/can.map.backup'
            ],
            dest: 'dist.js'
          }
        },
        uglify: {
          options: {
            banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
          },
          dist: {
            files: {
              'production.min.js': ['<%= concat.dist.dest %>']
            }
          }
        }
      });
      grunt.loadNpmTasks('grunt-contrib-uglify');
      grunt.loadNpmTasks('grunt-contrib-concat');
      grunt.registerTask('default', ['concat', 'uglify']);
    };

What are the major components of CanJS?

  1. can.Construct - inheritable constructor functions
  2. can.Observe - key-value binding
  3. can.Model - observes connected to a RESTful JSON interface
  4. can.view - template loading, caching, rendering
  5. can.EJS - live binding templates
  6. can.Control - declarative event bindings
  7. can.fixture: The can.fixture dependency is special because, normally, you don't want it to be a part of your final application; however, it can be very helpful during development. can.fixture.js allows you to simulate RESTful services. You can download it here.
  8. can.route: back button and bookmarking support. For many JavaScript MV* frameworks, routing divides an application into logical views and binds those views to Controllers. This is not how things work in CanJS. Routing in CanJS has nothing to do with binding views to Controllers. Rather, it has to do with AppState. In brief, CanJS maintains a reciprocal relationship between an application’s route and its state. In other words, if you change the state of an application, your route will change. If you change your route, your application’s state will change. This is a very powerful programming paradigm. For example, you can recreate a specific state in your application from any point, just by accessing a specific route.
  9. can.Components: A can.Component is like a mini web application. It contains the JavaScript, CSS, and HTML necessary to create a fully functional item. This makes can.Component’s portable, reusable, and encapsulated. can.Component’s are easy to test and easy to use. Building an application with them is kind of like building with Lego™. The secret to building large applications is to never build large applications. Rather, you build the components you need and link them together using the Application State and Routing to compose your application.
  10. Application State: An Application State object, or AppState object for short, is an observable object that, as its name implies, contains the state of your application.

What are the most important components in CanJS?

can.Observe: Observable objects provide a way for you to make changes to data and listen to those changes. Observables such as can.List and can.Map provide the foundation for updating model objects, views, and even routes in your app.

can.Construct: Many of the objects in CanJS are derived from can.Construct. Understanding it, therefore, will make it easier for you to understand other concepts. can.Construct provides a way to easily use the power of prototypal inheritance without worrying about hooking up all the particulars yourself.

How does CanJS handle memory leak?

Memory safety is really important, especially in long-lived, dynamic pages. CanJS combats this menace in two important and unique ways:

  1. Controls that unbind event handlers auto-magically
  2. A model store that does not leak

Controls that unbind event handlers auto-magically. Say you’re creating a tooltip widget that shows when you mouseover an element. You might use it like:

$("h1").bind("mouseenter",function(){
    $("<div>Undo</div>").tooltipFor(this)
});

Here’s an example of a leaking tooltip widget:

$.fn.tooltipFor = function(anchor){
    var $el = this
        .appendTo(document.body)
        .offset( $(anchor).offset() )

    $(anchor).bind("mouseleave",function(ev){
        $el.remove()
    });
}

On mouseleave, the tooltip element is removed from the DOM. However, there is nothing to remove mouseleave event handler. The event handler reference the $el variable via a closure. Because, the mouseleave event handler is not removed, the tooltip element still exist in memory even though it had been removed from the DOM. As a matter of fact, every time the user mouseover the h1 tag, a new mouseleave event handler is created.

CanJS solves this with templated event handlers. Here’s that same tooltip with can.Control:

var Tooltip = can.Control({
  init: function( el, options ) {
    el.appendTo(document.body)
      .offset( $(options.anchor).offset() )    
  },
  "{anchor} mouseleave": function( el, ev ) {
    this.element.remove();
  }
});

new Tooltip($("<div>Undo</div>"),{
  anchor : this
});

can.Control keeps a reference to all event handlers created for each control, listens for the control’s parent element to be removed, and unbinds all event handlers. Controls made with can.Control don’t leak.

A model store that does not leak. See http://canjs.com/guides/Why.html and http://bitovi.com/blog/2012/04/zombie-apocolypse.html

How flexible is CanJS?

CanJS’s tools are designed to work under almost every situation. Your server sends back XML with strange urls? That’s ok, overwrite can.Model.findAll or can.Model.models. Want some special teardown code for a control? Overwrite can.Control:destroy.

But our favorite bit of flexibility is how can.Observe works with nested data. It converts nested objects into observes automatically. For example:

var person = new can.Observe({
    name: { first: 'Justin', last: 'Meyer' },
    hobbies: [ 'programming', 'party rocking' ]
})
person.attr( 'name.first' ) //-> 'Justin'
person.attr( 'hobbies.0' ) //-> 'programming'

But most important, change events bubble, letting observes listen for when a nested property changes:

person.bind( 'change', function( ev, attr, how, newVal, oldVal ) {
    attr   //-> 'name.last'
    how    //-> 'set'
    newVal //-> 'Meyer'
    oldVal //-> 'Myer'
});
person.attr( 'name.last', 'Meyer' );

Want to share code between a Zepto mobile app and a jQuery desktop app? No problem. CanJS code (especially models) can be shared across libraries, and so can skill sets! Working on a Dojo project today and a YUI one tomorrow? Don’t throw away all of your skills.

What is the view modifer plugin?

Deferred are simply awesome for handling asynchronous behavior. Models produces deferreds and can.view consumes them. With the view modifiers plugin, you can load a template and its data in parallel and render it into an element with:

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

Hot. You can do this without the view modifiers plugin like:

can.view( 'todos.ejs', Todo.findAll() ).then(function( frag ) {
    $( '#todos' ).html( frag );
})

What is opt-in data binding?

Although can.ejs’s live-binding is super fast, setting up live data binding can be too slow in certain situations (like rendering a list of 1000 items). EJS’s live binding is opt-in. It only turns on if you are using the attr method. If the following template binds to a todo's name …

<li> <%= todo.attr('name') %> </li>

… the following doesn’t setup live-binding and renders much faster …

<li> <%= todo.name %> </li>

What is the purpose of can.stache?

can.stache contains utilities “for the loading, processing, rendering, and live-updating of templates”. In addition, can.stache is used to bind views to observable objects.

What is the first step in putting together a CanJS application?

The first step in putting together a CanJS app is sketching out the states of your application. I think that this is like planning out the pages and "components" that you will need. An state is like a stage (where the user is in the process of whatever the user is using your application for). For example, The order confirmation state shows the items the user selected, a total, and the personal information they’ve provided with the order. Note that this state also has a link to restart the ordering process, should the user want to place another order at the same restaurant.

The states can also be independent of each other. For example, the order history state can be access without having to actually place an order.

What is the purpose of the extend function that is part of can.Construct?

What is the purpose of can.Construct? How can we use can.Construct to create our own objects and extend our own objects? How many parameters can the extend function accept? How will the extend function behave if we pass it only one argument? How will the extend function behave if we pass it only 2 arguments? How will the extend function behave if we pass it 3 arguments?

can.Construct’s extend function is used to create “constructor functions”. Constructor functions create instances of objects. The extend function can take up to three arguments:

  1. name: string
  2. staticProperties: object
  3. instanceProperties: object

The extend function behaves differently depending on the number of arguments you pass it. If you pass it one argument, it will use the value you pass it to set its instanceProperties. If you pass it two arguments, it uses the first to set its staticProperties and the second to set its instanceProperties. If you pass in all three arguments, the first will set its name, the second its staticProperties, and the third its instanceProperties.

This pattern will apply to all objects in CanJS that have an extend function. For example, if we only want to set staticProperties we must call the function as follows:

can.Construct.extend({
        // Static properties here
    }, {
        // Blank object as second parameter
    }
);

This example is highlighted because calling a can.Construct with two parameters, the last of which is an empty object, is common. Also common is the mistake of ommitting the last parameter of the call, which can lead to unexpected behavior.

What is the purpose of the init function that is part of can.Construct?

The init function is called whenever a new instance of a can.Construct is created. init is where the bulk of your initialization code should go. Inside of the init function, the this keyword will refer to the new object instance created by the constructor. Additionaly, this will contain the instance properties you pass to the constructor. A common thing to do in init is save the arguments passed into the constructor. An example is below:

var Person = can.Construct.extend({
    init: function(first, last) {
        this.first = first;
        this.last = last;
    }
});
var actor = new Person('Abe', 'Vigoda');

Why are can.List and can.Map sub-classes of can.Observe?

Observables are the subjects in the observer pattern. They let you create relationships between objects where one object (or objects) listens for and responds to changes in another object. Most of the core objects in CanJS are observables. Understanding how to effectively work with observables lies at the heart of understanding how to build successful CanJS applications.

can.Map and can.List are often extended to create observable types. For example, can.Model and can.route are based on can.Map, and a can.Component’s viewModel is a can.Map.

How can we create a can.Map object?

To create a Map, call new can.Map(object). This will give you a map with the same properties and values as the object you passed in to the can.Map constructor.

var pagination = new can.Map({page: 1, perPage: 25, count: 1388});
pagination.attr('perPage'); // 25

The difference is that now you can use other can.Map's functions to access properties of this object.

How can we create a can.List object?

To create a List, call new can.List(array). This will give you a List with the same elements as the array you passed into the can.List constructor.

var hobbies = new can.List(['programming', 'bball', 'party rocking']);
hobbies.attr(2); // 'party rocking'

The difference is that now you can use other can.List's function to work with this list.

What is the purpose of the attr function that is part of can.Map, can.List or other can.Observe objects?

The attr method is used to read a property from, or write a property to a can.Map or can.List. While you can read the properties of a can.Map or can.List directly off of the object, to take advantage of the observable functionality you must use the .attr syntax.

var pagination = new can.Map({page: 1, perPage: 25, count: 1388});
pagination.attr('perPage');     // 25
pagination.attr('perPage', 50);
pagination.attr('perPage');     // 50
pagination.attr({page: 10, lastVisited: 1});
pagination.attr(); // {page: 10, perPage: 50, count: 1388, lastVisited: 1}

How can we remove an attribute from a can.Map, can.List, or other can.Observe objects?

Properties can be removed by using removeAttr, which is equivalent to the delete keyword:

pagination.removeAttr('count');
pagination.attr(); // {page: 10, perPage: 50, lastVisited: 1}

What events are triggered when an attribute is changed for a can.Map object?

When a property on a Map is changed with attr, the Map will emit two events: A change event and an event with the same name as the property that was changed.

What are the two methods to listen for events on a can.Observe object?

When a property on a Map is changed with attr, the Map will emit two events: A change event and an event with the same name as the property that was changed. There are two ways you can listen for these events:

  1. Using the define plugin
  2. Using the bind function

How can we listen to events on can.Observe objects using the bind function?

You can also listen for events by using bind, however this is less common:

// In this example, the chanage to pagination’s perPage attribute,
// on line 16, is responded to by the functions listening to 
// pagination’s change and perPage attributes. Note the values passed
// in to the functions when they are called.
pagination.bind('change', function(event, attr, how, newVal, oldVal) {
    attr;   // 'perPage'
    how;    // 'set'
    newVal; // 30
    oldVal; // 50
});
pagination.bind('perPage', function(event, newVal, oldVal) {
    newVal; // 30
    oldVal; // 50
});
pagination.attr('perPage', 30);

How can we stop listening for events on a can.Observe object using the unbind function?

var timesChanged = 0,
    changeHandler = function() { timesChanged++; },
    obs = new can.Map({value: 10});
obs.bind('change', changeHandler);
obs.attr('value', 20);
timesChanged; // 1
obs.unbind('change', changeHandler);
obs.attr('value', 30);
timesChanged; // 1

How can we iterate through a can.Map object?

If you want to iterate through the properties on a Map, use each:

var pagination = new can.Map({page: 10, perPage: 25, count: 1388});
pagination.each(function(val, key) {
    console.log(key + ': ' + val);
});

// The console shows:
// page: 10
// perPage: 25
// count: 1388

In the above code, the each method takes one parameter which is a function to be invoked for each key value pair.

How can we create our own observable types by extending can.Map, can.List, or can.Observe?

Extending a can.Map (or can.List) lets you create custom observable types. The following extends can.Map to create a Paginate type that has a .next() method:

Paginate = can.Map.extend({
    limit: 100,
    offset: 0,
    count: Infinity,
    page: function() {
        return Math.floor(this.attr('offset') / this.attr('limit')) + 1;
    },
    next: function() {
        this.attr('offset', this.attr('offset') + this.attr('limit') );
    }
});
var pageInfo = new Paginate();
pageInfo.attr("offset") //-> 0
pageInfo.next();
pageInfo.attr("offset") //-> 100
pageInfo.page()         //-> 2

What is the purpose of can.Map?

Implement observable map or object.

What is the purpose of can.List?

Implement observable arrays.

What is the relationship between can.List and can.Map?

can.List inherits from can.Map. A can.List works much the same way a can.Map does, with the addition of methods useful for working with arrays:

  1. indexOf: looks for an item in a List.
  2. pop: removes the last item from a List.
  3. push: adds an item to the end of a List.
  4. shift: removes the first item from a List.
  5. unshift: adds an item to the front of a List.
  6. splice: removes and inserts items anywhere in a List.

When these methods are used to modify a List events are emitted that you can listen for, as well. See the API for Lists for more information.

How can we create the AppState object?

CanJS suggests using a global appState object to manage the state of your application. The appState object is bound to two things:

  1. The application’s base template
  2. The application’s routing

Since you already know about creating instances of can.Map, creating an appState object, which is a can.Map, will be easy. Let’s see how this works. Open up your app.js file and update it as shown below.

    $(function () {
        var AppState = can.Map.extend({});
        var appState = new AppState();
        // Bind the application state to the root of the application
        $('#can-main').html(can.view('main.stache', appState));
        // Set up the routes
        can.route(':page', { page: 'home' });
        can.route(':page/:slug', { slug: null });
        can.route(':page/:slug/:action', { slug: null, action: null });
        $('body').on('click', 'a[href="javascript://"]', function(ev) {
            ev.preventDefault();
        });
        // Bind the application state to the can.route
        can.route.map(appState);
        can.route.ready();
        //appState.attr('page', 'restaurants');
        appState.bind('change', function(ev, prop, change, newVal, oldVal) {
            alert('Changed the “' + prop + '” property from “' + oldVal + '” to “' + newVal + '”.');
        });
    });

Why does CanJS bind the AppState object to the main.stache object?

It was mentioned earlier that we bound our AppState to the application’s main.stache. This is the key to connecting the AppState to our components. Because the appState object is bound to our main template, which includes the rest of the components in the app, these attributes will automatically be included in the scope of the components.

What is the purpose of can.Component?

A can.Component is like a self-contained, mini web application; in other words, it’s encapsulated. Because can.Component’s are encapsulated, they should each contain their own:

  1. View template file (.stache file)
  2. JavaScript file
  3. CSS file

This is why we created a components folder for our app—instead of, say, a js folder. Each component we develop will be in a folder that contains all the files that support that component. This makes components portable, enabling you to reuse them across projects. It also isolates them, making them easier to test and maintain.

How can we create a can.Component?

Put the following code inside components/restaurant_list/restaurant_list.js:

can.Component.extend({
    tag: 'pmo-restaurant-list',
    template: can.view('components/restaurant_list/restaurant_list.stache'),
    viewModel: {
        currentRestaurant: 'Hello Restaurant Customer'
    }
});

Notice that the above code define 3 things: a viewModel, a template, and a tag 'pmo-restaurant-list'. The tag property associates that can.Component with a specific, custom HTML tag. We will talk about tag a bit more further down below.

Put the following code to components/restaurant_list/restaurant_list.stache:

<h1>{{currentRestaurant}}</h1>

Finally, we need to add a reference to components/restaurant_list/restaurant_list.js in the index.html file:

<script src="components/restaurant_list/restaurant_list.js"></script>

Now, go back out to your app in the browser and refresh it. On the Restaurants page, you should see it printing: "Hello Restaurant Customer".

What is special about the extend method of can.Component?

Whenever you declare an object using can.Construct, it must be instantiated. Normally, you would either directly instantiate objects using the new keyword, or pass the constructor to an object that would create instances of it. can.Component is an exception.

All we have to do is declare the can.Component using its extend function. The extend function register your component with CanJS. When CanJS parses the main.stache file and encounters the custom tag defined by this component, it will automatically instantiate this component, generate the component’s view inside of its custom tag, and bind that view to your component’s scope.

What is a view model?

The viewModel object is the can.Component’s view model. The view model is an abstraction of the view that exposes public properties and functions. Any property or function defined on the view model object is available from the can.Component’s template as either a Stache data key, or a function. In our example above, we created the property currentRestaurant and then referenced it as a Stache data key in our template.

Perhaps the viewModel object is the context object for Handlebars (or the view object for Mustache).

Can we use the define plugin with the viewModel object of a can.Component?

Yes. can.List, can.Map, and other can.Observe objects can be the base class for other objects, and can be used for any purpose (there is really no limitation or restriction). In this case, if you wish to use a can.Map object as the viewModel object, you can. In fact, it is recommended:

can.Component.extend({
    tag: 'pmo-restaurant-list',
    template: can.view('components/restaurant_list/restaurant_list.stache'),
    viewModel: can.Map.extend({
        define: {
            state: {
                value: null,
                set: function(newState) {
                    if (newState) {
                        // Remove the city when the state changes
                        this.attr('city', null);
                    }
                    return newState;
                }
            },
            states: {
                value: [
                        {
                            cities: ['Green Bay', 'Milwaukee'],
                            name: 'Wisconsin'
                        },
                        {
                            cities: ['Detroit', 'Ann Arbor'],
                            name: 'Michigan'
                        },
                        {
                            cities: ['Chicago', 'Peoria'],
                            name: 'Illinois'
                        }
                    ]
            },
            cities: {
                get: function() {
                    var state = this.attr('state');
                    return state && this.attr('citiesByState')[state];
                }
            },
            citiesByState: {
                get: function() {
                    var citiesByState = {};
                    this.attr('states').forEach(function(state) {
                        citiesByState[state.name] = state.cities;
                    });
                    return citiesByState;
                }
            },
            city: {
                value: null
            }
        }
    })
});

The template:

<div class="restaurants">
  <h2 class="page-header">Restaurants</h2>
  <form class="form">
    <div class="form-group">
      <label>State</label>
      <select can-value="{state}">
        {{^if state}}
        <option value="">Choose a state</option>
        {{/if}}
        {{#each states}}
        <option value="{{name}}">{{name}}</option>
        {{/each}}
      </select>
    </div>

    <div class="form-group">
      <label>City</label>
      <select can-value="city">
        {{^if city}}
        <option value="">Choose a city</option>
        {{/if}}
        {{#each cities}}
        <option>{{.}}</option>
        {{/each}}
      </select>
    </div>

  </form>
  <!-- Restaurants code will go here -->
</div>

Here we’re using the define plugin to set up the following properties:

  1. state: to keep track of the selected state
  2. states: with the list of states that can be selected
  3. city: capture the name of the city that’s selected
  4. citiesByState: an object that has the list of cities by state name
  5. cities: which is the list of cities for the selected state

In the state setter, we’re showing an alert when a new state is selected. If you refresh the Restaurants page, you should see a select element with the states as options; when you select a state, an alert will appear with the selected state’s name.

How can we set or get properties of the viewModel object?

Getting and setting are done through the attr function of the viewModel object, in this case this is bound to the scope, because we’re within a method of the scope. In the above example, we use the define plugin. We need to understand the define plugin a bit more. Anyway, getting and setting are done through the attr function of the viewModel object.

How can we have good readability and maintainability?

It’s considered a best practice to keep your can.Components thin. This helps with having good readability and maintainability. To accomplish this, you extract your scope from the can.Component into a can.Map:

var RestaurantListViewModel = can.Map.extend({
  define: {
    state: {
      value: null,
      set: function() {
        // Remove the city when the state changes
        this.attr('city', null);
      }
    },
    states: {
      value: [
        {
          cities: ['Green Bay', 'Milwaukee'],
          name: 'Wisconsin'
        },
        {
          cities: ['Detroit', 'Ann Arbor'],
          name: 'Michigan'
        },
        {
          cities: ['Chicago', 'Peoria'],
          name: 'Illinois'
        }
      ]
    },
    cities: {
      get: function() {
        var state = this.attr('state');
        return state && this.attr('citiesByState')[state];
      }
    },
    citiesByState: {
      get: function() {
        var citiesByState = {};
        this.attr('states').forEach(function(state) {
          citiesByState[state.name] = state.cities;
        });
        return citiesByState;
      }
    },
    city: {
      value: null
    }
  }
});
can.Component.extend({
  tag: 'pmo-restaurant-list',
  template: can.view('components/restaurant_list/restaurant_list.stache'),
  viewModel: RestaurantListViewModel
});

How can we create a can.Model class?

Open the models/state.js file and add the following code:

var State = can.Model.extend({
    findAll: 'GET /api/states'
}, {
    // Include second, empty parameter object to set instanceProperties
});

Because it is a can.Construct, can.Model.extend can take up to three parameters:

  1. name
  2. staticProperties
  3. instanceProperties

A can.Model’s staticProperties parameter has several reserved properties you can add that simplify accessing data from a JSON REST service. These properties are:

  1. findAll
  2. findOne
  3. create
  4. update
  5. destroy

The find*, create, update, and destroy functions are available directly off of the object definition (i.e., they are static). The destroy function is available off of specific instances of a can.Model.

Reminder: The number of parameters you pass in to an extend function is important. If you pass in a single parameter object, the extend function will use that to set the instanceProperties. If you pass in two parameter objects, the first object passed in will be used to set the staticProperties. The second parameter will be used to set the instanceProperties. Here, we only want to set the staticProperties, so we must pass in a second, empty object.

var MyModel = can.Model.extend({
    findAll: function () {
        // Static function
    }
}, {
    destroy: function () {
        // Instance function
    }
});

MyModel.findAll(); // Reference a function defined on the constructor
var modelInstance = new MyModel();
modelInstance.destroy(); // Reference a function defined on the prototype

What are the parameters for findAll, findOne, etc?

Perhaps, this is not mandate by CanJS. Perhaps, these can take a JSON object. Notice that in the first example above, findAll is not defined as a function.

How can we use can.fixture?

CanJS provides a handy utility, can.fixture, that we can use to easily mimic the functionality of connecting to a server. can.fixture intercepts an AJAX request and simulates a server response with a file or a function. You can use can.fixture to develop JavaScript independently of backend services.

can.fixture is not included with the base CanJS package. It’s a good practice to keep it separate from your production CanJS library, which is why we downloaded and used it a separate script tag, rather than including it with our custom download. If you use can.fixture during development, remember to remove it once you need to connect to your REST services.

Add the following code to the models/fixtures.js file:

can.fixture('GET /api/states', 'models/states.json');

The first argument to can.fixture, GET /api/states, tells CanJS to intercept any GET requests to the resource /api/states. The second argument is a path to a file with the data the fixture will return. Because we’re simulating a findAll function, we need to return an array. The findAll function expects an array. By default, if it does not receive one, it will throw an error. If you need to connect to services that return data that doesn’t match the expected return type of the find* functions, don’t fret. There are ways to manage this, which we’ll work with later on.

Let’s also create a fixture that will respond to our requests for the list of cities for each state. This one is going to be a little different because we want to be able to return a different list depending on which state is included in the request. Thankfully, can.fixture is flexible and allows you to dynamically respond to requests. Let’s add the following code to the models/fixtures.js file:

can.fixture('GET /api/cities', function(request, response) {
    can.ajax({
        url: 'models/' + request.data.state + '.json',
        success: function(data) {
            response(data);
        }
    });
});

The first argument to can.fixture, GET /api/cities, is similar to our restaurants example: we’re setting up this fixture to intercept any GET requests to /api/cities. The second argument, however, is different: it is a function that returns the data we want to get when the application makes a service call. In our example, we’re making an AJAX request (via can.ajax) to get the fixture data from a JSON file, then responding to the request with the data we fetched.

How can we connect our data model to our view model?

Open up components/restaurant_list/restaurant_list.js, find the states property:

states: {
    value: [
        {
            cities: ['Green Bay', 'Milwaukee'],
            name: 'Wisconsin'
        },
        {
            cities: ['Detroit', 'Ann Arbor'],
            name: 'Michigan'
        },
        {
            cities: ['Chicago', 'Peoria'],
            name: 'Illinois'
        }
    ]
},

and replace it with:

states: {
    get: function() {
        return State.findAll({});
    }
},

In the same file, find the cities property:

cities: {
    get: function() {
        var state = this.attr('state');
        return state && this.attr('citiesByState')[state];
    }
},

and replace it with this:

cities: {
    get: function() {
        var state = this.attr('state');
        return state ? City.findAll({ state: state }) : null;
    }
},

You can remove the citiesByState property since we won’t be using it anymore. Let’s also update the components/restaurant_list/restaurant_list.stache file to match the changes we made in the view model. The most significant change is that our cities and states properties now return a promise instead of just an array. Find the form element:

      <form class="form">
        <div class="form-group">
          <label>State</label>
          <select can-value="{state}">
            {{^if state}}
            <option value="">Choose a state</option>
            {{/if}}
            {{#each states}}
            <option value="{{name}}">{{name}}</option>
            {{/each}}
          </select>
        </div>
        <div class="form-group">
          <label>City</label>
          <select can-value="city">
            {{^if city}}
            <option value="">Choose a city</option>
            {{/if}}
            {{#each cities}}
            <option>{{.}}</option>
            {{/each}}
          </select>
        </div>
      </form>

and replace it with:

      <form class="form">
        <div class="form-group">
          <label>State</label>
          <select can-value="{state}" {{#if states.isPending}}disabled{{/if}}>
            {{#if states.isPending}}
              <option value="">Loading...</option>
            {{else}}
              {{^if state}}
              <option value="">Choose a state</option>
              {{/if}}
              {{#each states.value}}
              <option value="{{short}}">{{name}}</option>
              {{/each}}
            {{/if}}
          </select>
        </div>
        <div class="form-group">
          <label>City</label>
          <select can-value="city" {{^if state}}disabled{{/if}}>
            {{#if cities.isPending}}
              <option value="">Loading...</option>
            {{else}}
              {{^if city}}
              <option value="">Choose a city</option>
              {{/if}}
              {{#each cities.value}}
              <option>{{name}}</option>
              {{/each}}
            {{/if}}
          </select>
        </div>
      </form>

What are different way to invoke the findAll method?

There are a few ways to call a findAll function on a can.Model. The first way is to call the function explicitly. Using the State model as an example, that would look like this:

State.findAll({ /* paramsObject */ },
    function(returnedObject){
        // ...
    },
    function(errorObject){
        // ...
    });

We also have the ability to use can.Deferred, which allows us to chain callback functions off of each other. Using this method, we could write our findAll like this:

State.findAll({ /* paramsObject */ })
    /* When the API call succeeds, .done() is called */
    .done(function(returnedObject) {
        // ...
    })
    /* When the API call errors, .fails() is called */
    .fail(function(errorObject) {
        // ...
    });

Both are acceptable, but the Deferred method is preferred as it more explicitly states which callback function is which.

What are the properties of a promise?

restaurants: {
    get: function(){
        var city = this.attr('city'),
            state = this.attr('state');
        return state && city ?
            Restaurant.findAll({
                'address.state': state,
                'address.city': city
            }) : null;
    }
}

Here, we’re adding a new restaurants property that is a promise returned by can.Model.findAll() (if a city and state are selected). This promise has a few properties:

  1. isPending: indicates that the promise hasn’t been resolved or rejected
  2. isResolved: indicates that the promise has been resolved
  3. value: the value of the resolved promise

And in our template, we have:

{{#if restaurants.isPending}}
<div class="restaurant loading"></div>
{{/if}}
{{#if restaurants.isResolved}}
{{#each restaurants.value}}
<div class="restaurant">
  <img src="{{images.thumbnail}}" width="100" height="100">
  <h3>{{name}}</h3>
  {{#address}}
  <div class="address">
    {{street}}<br />{{city}}, {{state}} {{zip}}
  </div>
  {{/address}}
  <div class="hours-price">
    $$$<br />
    Hours: M-F 10am-11pm
    <span class="open-now">Open Now</span>
  </div>
  <a class="btn" can-href="{ page='restaurants' slug=slug }">Place My Order</a>
  <br />
</div>
{{/each}}
{{/if}}

You’ll notice the {{#if restaurants.isPending}} and {{#if restaurants.isResolved}} lines; the first is for showing a loading indicator while the restaurants are being loaded, and the second is for showing the list of restaurants once they’ve been fetched from the server (or in our case, from the fixtures). After they have, {{#each restaurants.value}} iterates over the list of restaurants to show them on the page.

How should the content of the fixture file look like?

The models/fixtures.js should look like:

can.fixture('GET /api/restaurants', 'models/restaurants.json');
can.fixture('GET /api/restaurants/{_id}', 'models/spago.json');

The first argument to can.fixture, GET /api/states, tells CanJS to intercept any GET requests to the resource /api/states. The second argument is a path to a file with the data the fixture will return.

Let’s also create a fixture that will respond to our requests for the list of cities for each state. This one is going to be a little different because we want to be able to return a different list depending on which state is included in the request. Thankfully, can.fixture is flexible and allows you to dynamically respond to requests. Let’s add the following code to the models/fixtures.js file:

can.fixture('GET /api/cities', function(request, response) {
    can.ajax({
        url: 'models/' + request.data.state + '.json',
        success: function(data) {
            response(data);
        }
    });
});

The first argument to can.fixture, GET /api/cities, is similar to our restaurants example: we’re setting up this fixture to intercept any GET requests to /api/cities. The second argument, however, is different: it is a function that returns the data we want to get when the application makes a service call. In our example, we’re making an AJAX request (via can.ajax) to get the fixture data from a JSON file, then responding to the request with the data we fetched.

Because can.fixture intercept the AJAX calls, the above can.ajax is really returning a fixture. We can use this trick if we need to return different fixtures for different circumstance, but how does this work? Perhaps, can.fixture automatically invoke the function with appropriate request and response objects so that we can inspect those to form appropriate URL, and let can.fixture intercept the can.ajax call, and let the can.ajax call mechanism works. The success function is nothing special. It is just the regular success function that are part of can.ajax.

What is the proper way to think and use can.Component?

Let’s edit the index.html file by replacing these lines:

<!-- Replace with order component script -->
<!-- Replace with order details component script -->
<!-- Replace with order history component script -->
<!-- Replace with order list component script -->
<!-- Replace with order phone component script -->

with:

<script src="components/order/order.js"></script>
<script src="components/order_details/order_details.js"></script>
<script src="components/order_list/order_list.js"></script>
<script src="components/order_history/order_history.js"></script>
<script src="components/order_phone/order_phone.js"></script>

As you can see, order is structured as one component, "order details" is structured as another component, etc.

How can we handle standard DOM event?

CanJS makes it easy to handle any any standard DOM event, such as a change event, in your component. To add an event handler, we have to make changes in two places:

  1. The view template
  2. The can.Component view model

Let’s build a phone-validator component to collect this information, and add some event handling to validate the field as the user types.

There are two ways you can add event handling to an element:

  1. by adding an attribute with the event name prefixed by can-.
  2. by adding an attribute with the event name surrounded in parenthesis, e.g., (click).
<!--Example using can- syntax-->
<input name="phone" type="text" can-keyup="{setPhoneValue @element.val}">

<!--Example using () syntax-->
<input name="phone" type="text" (keyup)="{setPhoneValue @element.val}">

Of these, the preferred method is to use parenthesis to surround the event name. Again, any standard DOM event is supported.

In addition to defining an event, you can pass certain predefined parameters to the method that handles the event. These parameters include:

  1. @element - The can.$ wrapped element where the event occurred.
  2. @event - The event object—or properties off of that object.
  3. @viewModel - If the element is a can.Component, the component's viewModel.
  4. @context - The current context.

You are not limited to these parameters. Any valid value can be passed in to the handler method. Separate method parameters with a space, e.g. {{myMethod arg1 arg2}}

Let’s open the components/order_phone/order_phone.stache file and add the following:

<div class="form-group{{#if error}} has-error{{/if}}">
  <label>Phone:</label>
  <input name="phone" type="text" (keyup)="{setPhoneValue @element.val}">
  {{#if error}}
    {{#eq order.phone '911'}}
      <p>That's not your real number :-(</p>
    {{else}}
      <p>Please enter a phone number in the format 555-555-5555</p>
    {{/eq}}
  {{/if}}
</div>

Notice the <input /> element with a (keyup) event handler. Whenever there is a keyup event in the input, the code in the value will be executed. We’re also passing @element.val to the setPhoneValue helper. Let’s add the component’s JavaScript to the components/order_phone/order_phone.js file:

var PhoneViewModel = can.Map.extend({
    error: function(){
        var phone = this.attr("order").attr("phone");
        return phone && (!/^(\d|-)*$/.test(phone) || phone === "911");
    },
    setPhoneValue: function(val){
        this.attr('order').attr('phone', val);
    }
});

can.Component.extend({
    tag: 'phone-validator',
    viewModel: PhoneViewModel,
    template: can.view('components/order_phone/order_phone.stache')
});

Here you can see the setPhoneValue helper function, which takes the val passed to it by the template and sets the phone property of the component’s order property to val.

But how do errors show up? The template is using the error property on the component, which looks like this:

error: function(){
    var phone = this.attr("order").attr("phone");
    return phone && (!/^(\d|-)*$/.test(phone) || phone === "911");
},

Notice that the error property uses this.attr("order").attr("phone") in its getter. Because of CanJS’s observables, CanJS is aware of us setting that value in our setPhoneValue helper, and thus only runs the getter again (called “recomputing the value”) when the value has changed. When the setPhoneValue helper sets the value, CanJS recomputes the error property’s value, which will return an error if you type “911” or anything that doesn’t look like a phone number.

Note that you can place as many event handlers as you need on an element. Adding event handlers in this way directly binds the events to the element. This can impact performance in situations where you have many elements to bind events to. For more performant event binding, you can use the can.Component’s events property.

How can we save and update our data model to the database?

In the components/order/order.js:

placeOrder: function() {
    var order = this.attr('order');
    this.attr('saveStatus', order.save());
    return false;
},
  • The first line in the getter function gets the order,
  • the second sets the saveStatus property on the component’s view model to whatever the save method on the order object returns, and
  • the third line returns false to stop the form element’s default submission behavior.

Let’s look at a few items in the code above. Unlike data access functions (e.g., findAll, findOne), which are called statically off of the prototype, the save, update, and delete functions are called off of a specific instance of a model. So, if we want to create a new order, we will need to work with an instance of the Order model.

To provide fixture support for saving our can.Model, open up models/fixtures.js and add the following fixture:

can.fixture({
    'POST /api/orders': function(request, response){
        var data = request.data;
        response(can.extend({}, data, {
            "_id":"556f1503fdf0425207000001"
        }));
    },
    'GET /api/orders': 'models/orders.json'
});

Here, you can see that we’re implementing the save functionality by responding to POST requests to /api/orders with the original request data, plus an _id property. We also added support for GET requests to /api/orders so we can provide order history functionality.

What does can.Model allow us to do / What is the purpose of can.Model?

In CanJS, can.Model adds functionality to can.Map to work with data on a server. It enables you to:

  • Get and modify data from a server
  • Listen to changes made to the data on the server
  • Unify service data with other objects in your application

can.Model allows you to access data from a server easily:

var Todo = can.Model.extend({
    findAll: 'GET /todos',
    findOne: 'GET /todos/{id}',
    create:  'POST /todos',
    update:  'PUT /todos/{id}',
    destroy: 'DELETE /todos/{id}'
},{});

Using any server with a REST interface, can.Model enables create, read, update, and destroy a resource.

How does CanJS implement data driven controls?

The "data driven control" term refers to developing application controls such that changes in the data / state automatically update the UI. In CanJS, using can.Mustache, data driven controls are structured with the following architecture:

  1. Controls maintain UI state, via can.Map or can.compute observable objects.
  2. Views (written using can.Mustache) are rendered once and represent the UI state visually
  3. View helpers (can.Mustache helper functions) translate UI state to DOM state.
  4. Event handlers in the UI controls strictly maintain and update the UI state objects.

The control update the state, which trigger the change event handler within the template engine, which automatically update the DOM. The reason for this approach is simplicity. You only worry about how to represent your data once, while creating your template (and associated helpers). Set it and forget it. Any time data or state changes, those changes are automatically reflected.

When you push the todo, the DOM will reflect the change automatically. A few concrete advantages of doing things this way are:

  1. There’s no need for selector strings in your UI code. These have a tendency to change often, breaking brittle selector strings.
  2. Enforces strict separation between template and control logic. Previously, writing a Control required intimate knowledge of the DOM structure and rules connecting the state to the DOM. Code like this is harder to read and maintain. With live binding, the template (or helpers) contain all of this logic. The Control just maintains application logic.
  3. The performance will be much better, compared to the “Render Everything” example above. can.Mustache renders just the smallest portion of the template that is required. If a todo is pushed, a single LI will be created and appended to the UL.

When you use this pattern yourself, there are a few rules to live by:

  1. No DOM manipulation code in the control (except template helpers)
  2. Render templates only once (during control initialization)
  3. Connect complex state to the DOM with a Mustache helper

1. No DOM manipulation code in the control (except template helpers). This includes adding classes! For example, imagine you need to keep track of the currently “active” todo. If you set the className directly in the control, you’ll have to query the DOM to figure out which todo is active (or worse, keep track of this information twice). This is bad!

Instead, keep track of state on the data itself, and use Mustache helpers to tie that state to the DOM. In this example:

{% raw %}
<!-- In the template: -->
<li class='todo {{#if active}}active{{/if}}' {{data 'todo'}}>{{title}}</li>
{% endraw %}

And in the control:

".todo click": function(el, ev){
  var selected = el.data('todo');
  this.todos.each(function(todo){
    todo.attr('active', todo === selected);
  });
}

2. Render templates only once (during control initialization). Avoid re-rendering templates. Pre-live binding, the pattern was to render the control template each time something changed. The pattern now is to render templates in your init method, only once, like this:

init: function(){
  this.element.html(renderTemplate(data));
}

3. Connect complex state to the DOM with a Mustache helper. Any attributes accessed with the attr method in a Mustache helper will set up a live binding, so translate any non-trivial state logic to the DOM with helpers like:

this.element.html(renderTemplate(data, 
// helpers are the second argument
{
  // if there's an active todo, set class to 'show'
  editButtonVisible: function(){
    var active = false;
    this.todos.each(function(todo){
      if(todo.attr('active') === true){
        active = true;
      }
    });
    if(active) return 'show';
  }
}));

And use the helper in the template like:

{% raw %}
<div class='edit {{editButtonVisible}}'></div>
{% endraw %}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License