Skip to content

Instantly share code, notes, and snippets.

@jupiterjs
Forked from moschel/JavaScriptMVC.md
Created May 24, 2011 16:58
Show Gist options
  • Save jupiterjs/989117 to your computer and use it in GitHub Desktop.
Save jupiterjs/989117 to your computer and use it in GitHub Desktop.

Revisions

  1. JupiterJS revised this gist Jun 8, 2011. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -64,8 +64,8 @@ When a new class instance is created, it calls the class's <code>init</code> met
    }
    });

    var justin = new Person("Payal");
    assertEqual( justin.speak() , 'I am Payal.' );
    var payal = new Person("Payal");
    assertEqual( payal.speak() , 'I am Payal.' );

    ### Calling base methods

  2. JupiterJS revised this gist Jun 8, 2011. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -64,8 +64,8 @@ When a new class instance is created, it calls the class's <code>init</code> met
    }
    });

    var justin = new Person("Justin");
    assertEqual( justin.speak() , 'I am Justin.' );
    var justin = new Person("Payal");
    assertEqual( justin.speak() , 'I am Payal.' );

    ### Calling base methods

  3. JupiterJS revised this gist Jun 8, 2011. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -6,7 +6,7 @@ JavaScriptMVC (JMVC) is an open-source jQuery-based JavaScript framework. It is

    Yet every part of JavaScriptMVC can be used without every other part, making the library lightweight. Its Class, Model, View, and Controller combined are only 7k minified and compressed, yet even they can be used independently. JavaScriptMVC's independence lets you start small and scale to meet the challenges of the most complex applications on the web.

    This chapter covers JavaScriptMVC's $.Class, $.Model, $.View, and $.Controller. The following describes each component:
    This chapter covers __only__ JavaScriptMVC's $.Class, $.Model, $.View, and $.Controller. The following describes each component:

    - <code>$.Class</code> - JavaScript based class system
    - <code>$.Model</code> - traditional model layer
  4. JupiterJS revised this gist May 30, 2011. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -53,7 +53,7 @@ If you want to create a sub-class, simply call the the base class with the sub-c

    ### Instantiation

    When a new class is created, it calls the class's <code>init</code> method with the arguments passed to the constructor function:
    When a new class instance is created, it calls the class's <code>init</code> method with the arguments passed to the constructor function:

    $.Class('Person',{
    init : function(name){
  5. JupiterJS revised this gist May 30, 2011. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -293,7 +293,7 @@ Now the nextPrev plugin can set offset with reckless abandon:

    ### Defaults

    We can add default values to Paginate instances by setting the static defaults property. When a new paginate instance is created, if no value is provided, it will use the default value.
    We can add default values to Paginate instances by setting the static <code>defaults</code> property. When a new paginate instance is created, if no value is provided, it initializes with the default value.

    $.Model('Paginate',{
    defaults : {
  6. JupiterJS revised this gist May 30, 2011. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -271,7 +271,7 @@ There are a few ways to make the Paginate model more useful. First, by adding s

    Settter methods are model prototype methods that are named <code>setNAME</code>. They get called with the val passed to <code>model.attr(NAME, val)</code> and a success and error callback. Typically, the method should return the value that should be set on the model instance or call error with an error message. Success is used for asynchronous setters.

    The following paginate model uses setters to prevent negative counts and offsets and to prevent the offset from exceeding the count.
    The following paginate model uses setters to prevent negative counts the offset from exceeding the count by adding <code>setCount</code> and <codE>setOffset</code> instance methods.

    $.Model('Paginate',{
    setCount : function(newCount, success, error){
  7. JupiterJS revised this gist May 30, 2011. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -39,7 +39,7 @@ In the example above, instances of Animal have a <code>breathe()</code> method.
    var man = new Animal();
    man.breathe();

    If you want to create a sub-class, simply call the the base class with the sub-class' name and properties:
    If you want to create a sub-class, simply call the the base class with the sub-class's name and properties:

    Animal("Dog",{
    wag : function(){
    @@ -53,7 +53,7 @@ If you want to create a sub-class, simply call the the base class with the sub-c

    ### Instantiation

    When a new class is created, it calls the class' <code>init</code> method with the arguments passed to the constructor function:
    When a new class is created, it calls the class's <code>init</code> method with the arguments passed to the constructor function:

    $.Class('Person',{
    init : function(name){
    @@ -83,7 +83,7 @@ to provide a more 'classy' greating:

    ### Proxies

    Class' callback method returns a function that has 'this' set appropriately (similar to [$.proxy](http://api.jquery.com/jQuery.proxy/)). The following creates a clicky class that counts how many times it was clicked:
    Class's callback method returns a function that has 'this' set appropriately (similar to [$.proxy](http://api.jquery.com/jQuery.proxy/)). The following creates a clicky class that counts how many times it was clicked:

    $.Class("Clicky",{
    init : function(){
  8. JupiterJS revised this gist May 30, 2011. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -26,7 +26,7 @@ The download will come with minified and unminified versions of jQuery and the p

    ## Class

    JMVC's Controller and Model make use of their Class helper - $.Class. To create a class, call <code>$.Class(NAME, [classProperties, ] instanceProperties])</code>.
    JMVC's Controller and Model inherit from its Class helper - $.Class. To create a class, call <code>$.Class(NAME, [classProperties, ] instanceProperties])</code>.

    $.Class("Animal",{
    breathe : function(){
  9. JupiterJS revised this gist May 30, 2011. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -19,7 +19,7 @@ JavaScriptMVC's naming conventions deviate slightly from the traditional [Model-

    JavaScriptMVC can be used as a single download that includes the entire framework. But since this chapter covers only the MVC parts, go to the [download builder](http://javascriptmvc.com/builder.html), check Controller, Model, and View's EJS templates and click download.

    The download will come with minified and unminified versions of jQuery and the plugins you selected (plus their dependencies, like $.Class). Load these with script tags in your page:
    The download will come with minified and unminified versions of jQuery and the plugins you selected. Load these with script tags in your page:

    <script type='text/javascript' src='jquery-1.6.1.js'></script>
    <script type='text/javascript' src='jquerymx-1.0.custom.js'></script>
  10. @moschel moschel revised this gist May 29, 2011. 1 changed file with 11 additions and 11 deletions.
    22 changes: 11 additions & 11 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -443,9 +443,9 @@ The following table details how to use the task model to CRUD tasks.
    error( jqXHR)
    ) -> taskDeferred</code></pre></td>
    <td><p>To create an instance of a model on the server, first create an instance with <code>new Model(attributes)</code>. Then call <code>save()</code>.</p>
    <p>Save checks if the task has an id. In this case it does not so save makes a create request with the tasks attributes. Save takes two parameters:</p>
    <p>Save checks if the task has an id. In this case it does not so save makes a create request with the task's attributes. Save takes two parameters:</p>
    <ul>
    <li><code>success</code> - a function that gets called if the save is successful. Success gets called with the <code>task<code> instance and the <code>data</code> returned by the server.</li>
    <li><code>success</code> - a function that gets called if the save is successful. Success gets called with the <code>task</code> instance and the <code>data</code> returned by the server.</li>
    <li><code>error</code> - a function that gets called if there is an error with the request. It gets called with jQuery's wrapped XHR object.</li>
    </ul>

    @@ -461,8 +461,8 @@ The following table details how to use the task model to CRUD tasks.
    <td>Retrieves a single task from the server. It takes three parameters:
    <ul>
    <li><code>params</code> - data to pass to the server. Typically an id like: <code>{id: 2}</code>.</li>
    <li><code>success</code> - a function that gets called if the request is succesful. Success gets called with the <code>task<code> instance.</li>
    <li><code>error</code> - a function that gets called if there is an error with the request. It gets called with jQuery's wrapped XHR object.</li>
    <li><code>success</code> - a function that gets called if the request is succesful. Success gets called with the <code>task</code> instance.</li>
    <li><code>error</code> - a function that gets called if there is an error with the request.</li>
    </ul>

    findOne returns a deferred that resolves to the task.
    @@ -476,16 +476,16 @@ The following table details how to use the task model to CRUD tasks.
    <td>Retrieves an array of tasks from the server. It takes three parameters:
    <ul>
    <li><code>params</code> - data to pass to the server. Typically, it's an empty object (<code>{}</code>) or filters: <code>{limit: 20, offset: 100}</code>.</li>
    <li><code>success</code> - a function that gets called if the request is succesful. Success gets called with an array of task instances. It can also get called with a $.Model.List of task instances.</li>
    <li><code>error</code> - a function that gets called if there is an error with the request. It gets called with jQuery's wrapped XHR object.</li>
    <li><code>success</code> - a function that gets called if the request is succesful. Success gets called with an array of task instances.</li>
    <li><code>error</code> - a function that gets called if there is an error with the request.</li>
    </ul>
    findOne returns a deferred that resolves to an array of tasks.
    </td>
    </tr>
    <tr>
    <td>Update a task</td>
    <td><pre><code>task.attr('name','take out recycling');
    task.save(
    task.save(
    success( task, data ),
    error( jqXHR)
    ) -> taskDeferred</code></pre></td>
    @@ -502,7 +502,7 @@ The following table details how to use the task model to CRUD tasks.
    <td><p>Destroys a task on the server. Destroy takes two parameters:</p>
    <ul>
    <li><code>success</code> - a function that gets called if the save is successful. Success gets called with the <code>task<code> instance and the <code>data</code> returned by the server.</li>
    <li><code>error</code> - a function that gets called if there is an error with the request. It gets called with jQuery's wrapped XHR object.</li>
    <li><code>error</code> - a function that gets called if there is an error with the request.</li>
    </ul>

    Destroy returns a deferred that resolves to the destroyed task.
    @@ -514,7 +514,7 @@ The <code>Task</code> model has essentially become a contract to our services!

    ### Type Conversion

    Did you notice how the server responded with createdAt values as numbers like <code>1303173531164</code>. This number is actually April 18th, 2011. Instead of getting a number back from <code>task.createAt</code>, it would be much more useful if it returns a JavaScript date created with <code>new Date(1303173531164)</code>. We could do this with a <code>setCreatedAt</code> setter. But, if we have lots of date types, this will quickly get repetitive.
    Did you notice how the server responded with createdAt values as numbers like <code>1303173531164</code>. This number is actually April 18th, 2011. Instead of getting a number back from <code>task.createdAt</code>, it would be much more useful if it returns a JavaScript date created with <code>new Date(1303173531164)</code>. We could do this with a <code>setCreatedAt</code> setter. But, if we have lots of date types, this will quickly get repetitive.

    To make this easy, $.Model lets you define the type of an attribute and a converter function for those types. Set the type of attributes on the static <code>attributes</code> object and converter methods on the static <code>convert</code> object.

    @@ -540,9 +540,9 @@ Task now converts createdAt to a Date type. To list the year of each task, writ

    ### CRUD Events

    Model publishes events when an instance has been created, updated, or destroyed. You can listen to these events globally on the Model or on an individual model instance. Use <code>MODEL.bind(EVENT, callback( ev, instance ) )</code> to listen for created, updated, or destroyed events.
    Model publishes events when an instance has been created, updated, or destroyed. You can listen to these events globally on the Model or on an individual model instance. Use <code>MODEL.bind(EVENT, callback( ev, instance ) )</code> to listen for created, updated, or destroyed events.

    Lets say we wanted to know when a task is created and add it to the page. And after it's been added to the page, we'll listen for updates on that task to make sure we are showing its name correctly. We can do that like:
    Lets say we wanted to know when a task is created and add it to the page. After it's been added to the page, we'll listen for updates on that task to make sure we are showing its name correctly. We can do that like:

    Task.bind('created', function(ev, task){
    var el = $('<li>').html(todo.name);
  11. @moschel moschel revised this gist May 29, 2011. 1 changed file with 11 additions and 10 deletions.
    21 changes: 11 additions & 10 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -260,9 +260,9 @@ Second, the logic protecting a negative offset or offset above the total count i
    JavaScriptMVC's model inherits from $.Class. Thus, you create a model class by inheriting from <code>$.Model(NAME, [STATIC,] PROTOTYPE)</code>:

    $.Model('Paginate',{
    classProperty: 'foo'
    staticProperty: 'foo'
    },{
    staticProperty: 'bar'
    prototypeProperty: 'bar'
    })

    There are a few ways to make the Paginate model more useful. First, by adding setter methods, we can limit what values count and offset can be set to.
    @@ -271,7 +271,7 @@ There are a few ways to make the Paginate model more useful. First, by adding s

    Settter methods are model prototype methods that are named <code>setNAME</code>. They get called with the val passed to <code>model.attr(NAME, val)</code> and a success and error callback. Typically, the method should return the value that should be set on the model instance or call error with an error message. Success is used for asynchronous setters.

    The following paginate model uses setters to prevent negative counts and offsets and prevent the offset from exceeding the count.
    The following paginate model uses setters to prevent negative counts and offsets and to prevent the offset from exceeding the count.

    $.Model('Paginate',{
    setCount : function(newCount, success, error){
    @@ -293,7 +293,7 @@ Now the nextPrev plugin can set offset with reckless abandon:

    ### Defaults

    We can add default values to Paginate instances by setting the static defaults property object that contains the default attributes. When a new paginate instance is created, if no value is provided, it will use the default value.
    We can add default values to Paginate instances by setting the static defaults property. When a new paginate instance is created, if no value is provided, it will use the default value.

    $.Model('Paginate',{
    defaults : {
    @@ -306,11 +306,12 @@ We can add default values to Paginate instances by setting the static defaults p
    setOffset : function(newOffset, success, error){ ... }
    })

    var paginate = new Paginate();
    var paginate = new Paginate({count: 500});
    assertEqual(paginate.limit, 100);
    assertEqual(paginate.count, 500);


    This is getting sexu, but the Paginate model can make it event easier to move to the next and previous page and know if it's possible by adding helper methods.
    This is getting sexy, but the Paginate model can make it even easier to move to the next and previous page and know if it's possible by adding helper methods.

    ### Helper methods

    @@ -343,7 +344,7 @@ Helper methods are prototype methods that help set or get useful data on model i
    }
    })

    Thus jQuery widget becomes much more refined:
    Thus, our jQuery widget becomes much more refined:

    $.fn.nextPrev = function(paginate){
    this.delegate('.next','click', function(){
    @@ -361,11 +362,11 @@ Thus jQuery widget becomes much more refined:

    ### Service Encapsulation

    We've just seen how $.Model is useful for modeling client side state. However, for most applications, the critical data on the server, not on the client. The client needs to create, retrieve, update and delete (CRUD) data on the server. Maintaining the duality of data on the client and server is tricky business. $.Model is used to simplify this problem.
    We've just seen how $.Model is useful for modeling client side state. However, for most applications, the critical data is on the server, not on the client. The client needs to create, retrieve, update and delete (CRUD) data on the server. Maintaining the duality of data on the client and server is tricky business. $.Model is used to simplify this problem.

    $.Model is extremely flexible. It can be made to work with all sorts of services types and data types. This book covers only how $.Model works with the most common and popular type of service, Representational State Transfer (REST), and data type, JSON.
    $.Model is extremely flexible. It can be made to work with all sorts of services types and data types. This book covers only how $.Model works with the most common and popular type of service and data type: Representational State Transfer (REST) and JSON.

    A REST service uses urls and the HTTP verbs POST, GET, PUT, DELETE to create, retrieve, update, and delete data respectively. For example, take a tasks service that allowed you to create, retrieve, update and delete tasks might look like:
    A REST service uses urls and the HTTP verbs POST, GET, PUT, DELETE to create, retrieve, update, and delete data respectively. For example, a tasks service that allowed you to create, retrieve, update and delete tasks might look like:

    <table>
    <tr>
  12. @moschel moschel revised this gist May 29, 2011. 1 changed file with 6 additions and 6 deletions.
    12 changes: 6 additions & 6 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -177,7 +177,7 @@ This is similar to how JavaScriptMVC's model layer works.

    ## Model

    JavaScriptMVC's model and it associated plugins provide lots of tools around organizing model data such as validations, associations, lists and more. But the core functionality is centered around service encapsulation, type conversion, and events.
    JavaScriptMVC's model and its associated plugins provide lots of tools around organizing model data such as validations, associations, lists and more. But the core functionality is centered around service encapsulation, type conversion, and events.

    ### Attributes and Observables

    @@ -202,11 +202,11 @@ The paginate variable is now observable. We can pass it to pagination controls
    assertEqual( paginate.offset, 0 );
    assertEqual( paginate.attr('limit') , 20 );

    If we clicked the next button, we need to increment the offset. Change property values with <code>model.attr(NAME, VALUE). The following moves the offset to the next page:
    If we clicked the next button, we need to increment the offset. Change property values with <code>model.attr(NAME, VALUE)</code>. The following moves the offset to the next page:

    paginate.attr('offset',20);

    When paginate's state is changed by one control, the other controls need to be notified. You can bind to a specific attribute changs with <code>model.bind(ATTR, success( ev, newVal )</code> and update the control:
    When paginate's state is changed by one control, the other controls need to be notified. You can bind to a specific attribute change with <code>model.bind(ATTR, success( ev, newVal ) )</code> and update the control:

    paginate.bind('offset', function(ev, newVal){
    $('#details').text( 'Showing items ' + (newVal+1 )+ '-' + this.count )
    @@ -218,7 +218,7 @@ You can also listen to any attribute change by binding to the <code>'updated.att
    $('#details').text( 'Showing items ' + (newVal+1 )+ '-' + this.count )
    })

    Tthe following is a next-previous jQuery plugin that accepts paginate data:
    The following is a next-previous jQuery plugin that accepts paginate data:

    $.fn.nextPrev = function(paginate){
    this.delegate('.next','click', function(){
    @@ -251,9 +251,9 @@ Tthe following is a next-previous jQuery plugin that accepts paginate data:
    })
    };

    There are a few problems with this plugin. First, the logic protecting a negative offset or offset above the count is done in the plugin. This logic should be done in the model. Second, if the control is removed from the page, it is not unbinding itself from paginate. We'll address the first problem in the following sections and address the second problem when we discuss controllers.
    There are a few problems with this plugin. First, if the control is removed from the page, it is not unbinding itself from paginate. We'll address this when we discuss controllers.

    To fix the validation problem, we'll need to add additional constraints to limit what values limit, offset, and count can be. We'll need to create a pagination class.
    Second, the logic protecting a negative offset or offset above the total count is done in the plugin. This logic should be done in the model. To fix this problem, we'll need to add additional constraints to limit what values limit, offset, and count can be. We'll need to create a pagination class.

    ### Extending Model

  13. @moschel moschel revised this gist May 29, 2011. 1 changed file with 11 additions and 7 deletions.
    18 changes: 11 additions & 7 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -26,20 +26,20 @@ The download will come with minified and unminified versions of jQuery and the p

    ## Class

    JMVC's Controller and Model are based on it's Class helper - $.Class. To create a class, call <code>$.Class(NAME, [classProperties, ] instanceProperties])</code>.
    JMVC's Controller and Model make use of their Class helper - $.Class. To create a class, call <code>$.Class(NAME, [classProperties, ] instanceProperties])</code>.

    $.Class("Animal",{
    breathe : function(){
    console.log('breathe');
    }
    });

    In the example above, instances of Animal have a <code>breath()</code> method. We can create a new <code>Animal</code> instance and call <code>breathe()</code> on it like:
    In the example above, instances of Animal have a <code>breathe()</code> method. We can create a new <code>Animal</code> instance and call <code>breathe()</code> on it like:

    var man = new Animal();
    man.breathe();

    If you want to create a sub-class, simply call the the base class with the sub-classes name and properties:
    If you want to create a sub-class, simply call the the base class with the sub-class' name and properties:

    Animal("Dog",{
    wag : function(){
    @@ -51,9 +51,9 @@ If you want to create a sub-class, simply call the the base class with the sub-c
    dog.wag();
    dog.breathe();

    ### Instatiation
    ### Instantiation

    When a new class is created, it calls the class's <code>init</code> method with the arguments passed to the constructor function:
    When a new class is created, it calls the class' <code>init</code> method with the arguments passed to the constructor function:

    $.Class('Person',{
    init : function(name){
    @@ -83,7 +83,7 @@ to provide a more 'classy' greating:

    ### Proxies

    Class's callback method return a function that has 'this' set appropriately (similar to proxy). The following creates a clicky class that counts how many times it was clicked:
    Class' callback method returns a function that has 'this' set appropriately (similar to [$.proxy](http://api.jquery.com/jQuery.proxy/)). The following creates a clicky class that counts how many times it was clicked:

    $.Class("Clicky",{
    init : function(){
    @@ -103,7 +103,7 @@ Class's callback method return a function that has 'this' set appropriately (sim

    ### Static Inheritance

    Class lets you define inheritable static properties and methods. The following allows us to retrieve a person instance from the server by calling <code>Person.findOne(ID, success(person) )</code>. Success is called back with an instance of Person and has the <code>speak</code> method.
    Class lets you define inheritable static properties and methods. The following allows us to retrieve a person instance from the server by calling <code>Person.findOne(ID, success(person) )</code>. Success is called back with an instance of Person, which has the <code>speak</code> method.

    $.Class("Person",{
    findOne : function(id, success){
    @@ -133,6 +133,10 @@ Class provides namespacing and access to the name of the class and namespace obj
    Jupiter.Person.shortName; //-> 'Person'
    Jupiter.Person.fullName; //-> 'Jupiter.Person'
    Jupiter.Person.namespace; //-> Jupiter

    var person = new Jupiter.Person();

    person.Class.shortName; //-> 'Person'

    ### Model example

  14. @moschel moschel revised this gist May 29, 2011. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -17,9 +17,9 @@ JavaScriptMVC's naming conventions deviate slightly from the traditional [Model-

    ## Setup

    JavaScriptMVC can be used as a single download that includes its entire toolset. But this chapter covers only JavaScriptMVC's MVC parts. Instead of downloading the entire framework, go to the [download builder](http://javascriptmvc.com/builder.html), check Controller, Model, and View's EJS templates and click download.
    JavaScriptMVC can be used as a single download that includes the entire framework. But since this chapter covers only the MVC parts, go to the [download builder](http://javascriptmvc.com/builder.html), check Controller, Model, and View's EJS templates and click download.

    The download will come with minified and unminified versions of jQuery and the plugins you selected. Load these with script tags in your page:
    The download will come with minified and unminified versions of jQuery and the plugins you selected (plus their dependencies, like $.Class). Load these with script tags in your page:

    <script type='text/javascript' src='jquery-1.6.1.js'></script>
    <script type='text/javascript' src='jquerymx-1.0.custom.js'></script>
  15. @moschel moschel revised this gist May 29, 2011. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -2,18 +2,18 @@ The following is a VERY rough draft of an article I am working on for Alex MacCa

    ## Introduction

    JavaScriptMVC (JMVC) is an open-source jQuery-based JavaScript framework. It is nearly a comprehensive (holistic) front-end development framework; packaging utilities for testing, dependency management, documentation, and a host of useful jQuery plugins.
    JavaScriptMVC (JMVC) is an open-source jQuery-based JavaScript framework. It is nearly a comprehensive (holistic) front-end development framework, packaging utilities for testing, dependency management, documentation, and a host of useful jQuery plugins.

    Yet, every part of JavaScriptMVC can be used without every other part, making the library lightweight. It's Class, Model, View, and Controller combined are only 7k minified and compressed, yet even they can be used independently. JavaScriptMVC's independence lets you start small and scale to meet the challenges of the most complex applications on the web.
    Yet every part of JavaScriptMVC can be used without every other part, making the library lightweight. Its Class, Model, View, and Controller combined are only 7k minified and compressed, yet even they can be used independently. JavaScriptMVC's independence lets you start small and scale to meet the challenges of the most complex applications on the web.

    This chapter only covers JavaScriptMVC's $.Class, $.Model, $.View, and $.Controller. The following describes each component:
    This chapter covers JavaScriptMVC's $.Class, $.Model, $.View, and $.Controller. The following describes each component:

    - <code>$.Class</code> - JavaScript based class system
    - <code>$.Model</code> - traditional model layer
    - <code>$.View</code> - client side template system
    - <code>$.Controller</code> - jQuery widget factory

    JavaScriptMVC's naming conventions deviate slightly from the traditional [Model-View-Controller](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller#Concepts) design pattern. $.Controller is used to create traditional view controls, like pagination buttons and list. We'll also learn how to use $.Controller as a traditional controller, one that coordinates between the traditional views and models.
    JavaScriptMVC's naming conventions deviate slightly from the traditional [Model-View-Controller](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller#Concepts) design pattern. $.Controller is used to create traditional view controls, like pagination buttons and list, as well as traditional controllers, which coordinate between the traditional views and models.

    ## Setup

  16. @moschel moschel revised this gist May 29, 2011. 1 changed file with 7 additions and 5 deletions.
    12 changes: 7 additions & 5 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -2,16 +2,18 @@ The following is a VERY rough draft of an article I am working on for Alex MacCa

    ## Introduction

    JavaScriptMVC (JMVC) is an open-source jQuery-based JavaScript framework. It is nearly a comprehensive (holistic) front-end development framework; packaging utilities for testing, dependency management, documentation, and a host of useful jQuery plugins. Yet, every part of JavaScriptMVC can be used without every other part, making the library lightweight. It's Class, Model, View, and Controller combined are only 7k minified and compressed, yet even they can be used independently. JavaScriptMVC's independence lets you start small and scale to meet the challenges of the most complex applications on the web.
    JavaScriptMVC (JMVC) is an open-source jQuery-based JavaScript framework. It is nearly a comprehensive (holistic) front-end development framework; packaging utilities for testing, dependency management, documentation, and a host of useful jQuery plugins.

    This chapter only covers JavaScriptMVC's $.Class, $.Model, $.View, and $.Controller. JavaScriptMVC's naming conventions deviate slightly from the traditional Model-View-Controller design pattern. The following describes each component:
    Yet, every part of JavaScriptMVC can be used without every other part, making the library lightweight. It's Class, Model, View, and Controller combined are only 7k minified and compressed, yet even they can be used independently. JavaScriptMVC's independence lets you start small and scale to meet the challenges of the most complex applications on the web.

    - <code>$.Class</code> - JavaScript based class system.
    This chapter only covers JavaScriptMVC's $.Class, $.Model, $.View, and $.Controller. The following describes each component:

    - <code>$.Class</code> - JavaScript based class system
    - <code>$.Model</code> - traditional model layer
    - <code>$.View</code> - client side template system
    - <code>$.Controller</code> - jQuery plugin system that can serve as traditional controller or view.
    - <code>$.Controller</code> - jQuery widget factory

    We'll see how $.Controller is used to create traditional view controls, like pagination buttons and list. We'll also learn how to use $.Controller as a traditional controller, one that coordinates between the traditional views and models.
    JavaScriptMVC's naming conventions deviate slightly from the traditional [Model-View-Controller](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller#Concepts) design pattern. $.Controller is used to create traditional view controls, like pagination buttons and list. We'll also learn how to use $.Controller as a traditional controller, one that coordinates between the traditional views and models.

    ## Setup

  17. JupiterJS revised this gist May 28, 2011. 1 changed file with 0 additions and 200 deletions.
    200 changes: 0 additions & 200 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -558,203 +558,3 @@ The content for [$.View has been moved here](https://gist.github.com/996208)

    The content for [$.Controller has been moved here](https://gist.github.com/996204).

    ## FuncUnit

    Testing is an often overlooked part of front end development. Most functional testing solutions are hard to set up, expensive, use a difficult (non JavaScript) API, are too hard to debug, and are don't accurately simulate events. FuncUnit, JavaScriptMVC's testing solution, is designed to solve all these problems. No setup, firebug debugging, a jQuery-like API, and the most accurate possible event simulation make FuncUnit a comprehensive testing solution.

    ### Overview

    FuncUnit is a collection of several components:

    - jQuery - for querying elements and testing their conditions
    - QUnit - jQuery's unit test framework for setting up tests
    - Syn - an event simulation library made for FuncUnit that simulates clicks, types, drags
    - Selenium - used to programatically open and close browsers

    FuncUnit tests are written in JavaScript, with an API that looks identical to jQuery. To run them, you open a web page that loads your test. It opens your application in another page, runs your test, and shows the results.

    Alternatively, the same test will run from the command line, via Selenium. You run a command (or automate this in your continuous integration system), which launches a browser, runs your tests, and reports results.

    ### Getting Set Up

    Getting started with writing a FuncUnit test involves:

    1. Creating a funcunit.html page that loads a test script. The tests run within the QUnit framework, so the page needs some elements required by QUnit.

    <head>
    <link rel="stylesheet" type="text/css" href="funcunit/qunit/qunit.css" />
    <title>FuncUnit Test</title>
    </head>
    <body>
    <h1 id="qunit-header">funcunit Test Suite</h1>
    <h2 id="qunit-banner"></h2>
    <div id="qunit-testrunner-toolbar"></div>
    <h2 id="qunit-userAgent"></h2>
    <ol id="qunit-tests"></ol>
    <script type='text/javascript' src='steal/steal.js?steal[app]=myapp/test/funcunit/mytest.js'></script>
    </body>

    2. Create the test script. Steal funcunit, use QUnit's setup method to set your test up, and the test method to write your test.

    steal.plugins('funcunit').then(function(){
    module("yourapp test", {
    setup: function(){
    S.open("//path/to/your/page.html");
    }
    });
    test("First Test", function(){
    ok(true, "test passed");
    });
    })

    You should now have a working basic FuncUnit test. Open the page and see it run.

    ### Writing a Test

    Writing FuncUnit tests involves a similar repeated pattern:

    0. Opening a page (only do this once in the setup method).
    1. Perform some action (click a link, type into an input, drag an element)
    2. Wait for some condition to be true (an element becomes visible, an element's height reaches a certain value)
    3*. Check conditions of your page (does the offset of a menu element equal some expected value).

    * This can be done implicitly in step 2. If the conditions of your wait don't become true, the test will never complete and will fail.

    This pattern breaks down into the three types of methods in the FuncUnit API: actions, waits, and getters.

    Most commands (except open) follow the pattern of being called on a FuncUnit object, similar to a jQuery.fn method. The S method is similar to $, except it doesn't return a jQuery object. It accepts any valid jQuery selector and the results are chainable:

    S("a.myel").click().type("one").visible();


    #### QUnit Methods

    If you're familiar with QUnit, this section will be review. FuncUnit adds its own API on top of the QUnit framework.

    Module is the method used to define a collection of tests. It accepts a module name, and an object containing a setup method (called before each test), and a teardown method (called after each test).

    module("module name", {
    setup: function(){}
    teardown: function(){}
    });

    Test is the method used to define each test. Ok and equals are the two most common assertions. If their conditions are true, the assertion will pass. If any assertion fails, the test fails.

    #### Action Commands

    Actions include open, click, dblclick, rightclick, type, move, drag, and scroll.

    S("#foo").click();
    S("#foo").type("one");
    S("#foo").drag("#bar");

    They use the syn library to accurately simulate the event exactly as the browser would process it from a real user. Click causes the correct sequence of browser events in each browser (mousedown, click, mouseup, focus if its a form element).

    Note: Action commands don't actually get processed synchronously. This means you can't set a breakpoint on an action and step through the statements one by one. Each action command is asynchronous, so in order to prevent crazy nested callbacks everywhere, the FuncUnit API will add action commands to a queue, calling each after the previously queued item has completed.

    #### Wait Commands

    Waits are used to make your tests wait for some condition in the page to be true before proceeding. Waits are needed after almost every action to prevent your tests from being brittle. If you don't use a wait, you're assuming the action's results are instantaneous, which often, they aren't.

    Waits correspond to jQuery methods of the same name.

    Dimensions - width, height
    Attributes - attr, hasClass, val, text, html
    Position - position, offset, scrollLeft, scrollTop
    Selector - size, exists, missing
    Style - css, visible, invisible

    Waits, like actions, are asynchronous commands, and add themselves to the FuncUnit command queue, so they can't be inspected with breakpoints.

    Each wait accepts the attribute you'd expect it to to wait for its condition to be true. For example, width accepts a single number (the width to wait for). HasClass accepts a class string. Css accepts a property and its value.

    You can also pass a function instead of a wait value. This function will be called over and over until it is true, and then the wait is complete.

    S(".foo").width(10); // wait for foo to be 10px
    S(".foo").hasClass("bar") // wait for foo to have class "bar"
    S(".foo").visible() // wait for foo to be visible

    #### Getters

    Getters are used to test conditions of the page, usually within an assertion. They are actually the exact same method names as waits, listed above, but called without a wait condition.

    var width = S(".foo").width();
    var text = S(".foo").text();

    Every action and wait command accepts an optional callback function, which is called after the method completes. In these callbacks, you'd test page conditions with getters and do assertions.

    S(".foo").visible(function(){
    ok(S(".bar").size(), 5, "there are 5 bars");
    });

    You can set breakpoints inside these callbacks, test page conditions, and debug assertions that are failing.

    #### A Real Test

    Here's a test for an autocomplete widget.

    module("autosuggest",{
    setup: function() {
    S.open('autosuggest.html')
    }
    });

    test("JavaScript results",function(){
    S('input').click().type("JavaScript")

    // wait until we have some results
    S('.autocomplete_item').visible(function(){
    equal( S('.autocomplete_item').size(), 5, "there are 5 results")
    })
    });

    ### Running Tests

    There are two ways to run tests: browser and command line. To run from browser, just open your test page in the browser. Devs can use this while developing and debugging.

    To run from command line, open your test with funcunit/envjs.

    funcunit/envjs myapp/funcunit.html

    You can configure Selenium options (like browsers) in myapp/settings.js.

    FuncUnit = { browsers: ["*firefox", "*iexplore", "*safari", "*googlechrome"] };

    ## Special Events and Dom Extensions

    JavaScriptMVC is packed with jQuery helpers that make building a jQuery app easier and fast. Here's the some of the most useful plugins:

    ### CurStyles

    Rapidly retrieve multiple css styles on a single element:

    $('#foo').curStyles('paddingTop',
    'paddingBottom',
    'marginTop',
    'marginBottom');

    ### Fixtures

    Often you need to start building JS functionality before the server code is ready. Fixtures simulate Ajax responses. They let you make Ajax requests and get data back. Use them by mapping request from one url to another url:

    $.fixture("/todos.json","/fixtures/todos.json")

    And then make a request like normal:

    $.get("/todos.json",{}, function(){},'json')

    ### Drag Drop Events

    ### Hover

    ### Default

    ### Destroyed

    ### Hashchange




    ## Building a todo list

  18. JupiterJS revised this gist May 28, 2011. 1 changed file with 5 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -119,7 +119,7 @@ Class lets you define inheritable static properties and methods. The following
    })

    Person.findOne(5, function(person){
    alert( person.speak() );
    assertEqual( person.speak(), "I am Payal." );
    })

    ### Introspection
    @@ -370,15 +370,15 @@ A REST service uses urls and the HTTP verbs POST, GET, PUT, DELETE to create, re
    "id" : 2,
    "name" : "do the dishes",
    "acl" : "rw" ,
    "createdAt": 1303087131164 // April 17 2011
    "createdAt": 1303173531164 // April 18 2011
    }</code></pre></td>
    </tr>
    <tr>
    <td>Get a task</td><td>GET</td><td>/task/2</td><td></td><td><pre><code>{
    "id" : 2,
    "name" : "do the dishes",
    "acl" : "rw" ,
    "createdAt": 1303087131164 // April 17 2011
    "createdAt": 1303173531164 // April 18 2011
    }</pre></code></td>
    </tr>
    <tr>
    @@ -393,7 +393,7 @@ A REST service uses urls and the HTTP verbs POST, GET, PUT, DELETE to create, re
    "id" : 2,
    "name" : "do the dishes",
    "acl" : "rw" ,
    "createdAt": 1303087131164 // April 17 2011
    "createdAt": 1303173531164 // April 18 2011
    }]</code>
    </pre>
    </td>
    @@ -403,7 +403,7 @@ A REST service uses urls and the HTTP verbs POST, GET, PUT, DELETE to create, re
    "id" : 2,
    "name" : "take out recycling",
    "acl" : "rw" ,
    "createdAt": 1303087131164 // April 17 2011
    "createdAt": 1303173531164 // April 18 2011
    }</pre></code></td>
    </tr>
    <tr>
  19. JupiterJS revised this gist May 27, 2011. 1 changed file with 3 additions and 90 deletions.
    93 changes: 3 additions & 90 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -549,99 +549,12 @@ Lets say we wanted to know when a task is created and add it to the page. And a

    })

    ## $.View - Client Side Templates

    JavaScriptMVC's views are really just client side templates. Client side templates take data and return a string. Typically, the strings are HTML intended to be inserted into the DOM.
    ## $.View

    jQuery.View is a templating interface that takes care of complexities using templates:
    The content for [$.View has been moved here](https://gist.github.com/996208)

    - Convenient and uniform syntax
    - Template loading from html elements and external files.
    - Synchronous and asynchronous template loading.
    - Template preloading.
    - Caching of processed templates.
    - Bundling of processed templates in production builds.

    JavaScriptMVC comes pre-packaged with 4 different template engines:

    - EJS
    - JAML
    - Micro
    - Tmpl

    This tutorial uses EJS templates, but all the following techniques will work with any template engine with minor syntax difference.

    ### Basic Use

    When using views, you almost always want to insert the results of a rendered template into the page. jQuery.View overwrites the jQuery modifiers so using a view is as easy as:

    $("#foo").html('mytemplate.ejs',{message: 'hello world'})

    This code:

    1. Loads the template in file 'mytemplate.ejs'. It might look like:

    <h2><%= message %></h2>

    2. Renders it with {message: 'hello world'}, resulting in:

    <h2>hello world</h2>

    3. Inserts the result into the foo element. Foo might look like:

    <div id='foo'><h2>hello world</h2></div>


    ### jQuery Modifiers

    You can use a template with the following jQuery modifier methods:

    $('#bar').after('temp.ejs',{});
    $('#bar').append('temp.ejs',{});
    $('#bar').before('temp.ejs',{});
    $('#bar').html('temp.ejs',{});
    $('#bar').prepend('temp.ejs',{});
    $('#bar').replaceWidth('temp.ejs',{});
    $('#bar').text('temp.ejs',{});

    ### Loading from a script tag

    View can load from script tags or from files. To load from a script tag, create a script tag with your template and an id like:

    <script type='text/ejs' id='recipesEJS'>
    <% for(var i=0; i < recipes.length; i++){ %>
    <li><%=recipes[i].name %></li>
    <%} %>
    </script>

    Render with this template like:

    $("#foo").html('recipesEJS',recipeData)

    Notice we passed the id of the element we want to render.

    ### Packaging

    StealJS is JavaScriptMVC's dependency management and build system. Although not covered in this book, it's worth noting that StealJS is able to build templates into a production file. This makes the application load much faster as it doesn't have to wait for templates to load.

    ### Deferreds



    ### Asynchronous loading

    By default, retrieving requests is done synchronously. This is fine because StealJS packages view templates with your JS download.

    However, some people might not be using StealJS or want to delay loading templates until necessary. If you have the need, you can provide a callback paramter like:

    $("#foo").html('recipes',recipeData, function(result){
    this.fadeIn()
    });

    The callback function will be called with the result of the rendered template and 'this' will be set to the original jQuery object.


    ### $.Controller
    ## $.Controller

    The content for [$.Controller has been moved here](https://gist.github.com/996204).

  20. JupiterJS revised this gist May 27, 2011. 1 changed file with 2 additions and 130 deletions.
    132 changes: 2 additions & 130 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -641,137 +641,9 @@ However, some people might not be using StealJS or want to delay loading templat
    The callback function will be called with the result of the rendered template and 'this' will be set to the original jQuery object.


    ## $.Controller - jQuery plugin factory

    JavaScriptMVC's controllers are really a jQuery plugin factory. They can be used as a traditional view, for example, making a slider widget, or a traditional controller, creating view-controllers and binding them to models. If anything happens in your application, a controller should respond to it.

    Controllers are the most powerful piece of JavaScriptMVC and go the furthest towards helping you develop better JavaScript applications, with features like:

    - jQuery helper
    - auto bind / unbind
    - parameterized actions
    - defaults
    - pub / sub
    - automatic determinism

    ### Overview

    Controllers inherit from $.Class. Each Controller is instantiated on an HTML element. Controller methods, or actions, use event delegation for listen to events inside the parent element.

    $.Controller('Tabs',{
    click: function() {...},
    '.tab click' : function() {...},
    '.delete click' : function() {...}
    })
    $('#tabs').tabs();

    ### Creating a controller

    When a controller class is created, it automatically creates a jQuery.fn method of a similar name. These methods have three naming rules:

    1. Everything is lowercased
    1. "." is replaced with "_"
    2. "Controllers" is removed from the name

    $.Controller("Foo.Controllers.Bar") // -> .foo_bar()

    You create a controller by calling this jQuery.fn method on any jQuery collection. You can pass in options, which are used to set this.options in the controller.

    $(".thing").my_widget({message : "Hello"})

    ### Determinism

    Controllers provide automatic determinism for your widgets. This means you can look at a controller and know where in the DOM they operate, and vice versa.

    First, when a controller is created, it adds its underscored name as a class name on the parent element.

    <div id='historytab' class='history_tabs'></div>

    You can look through the DOM, see a class name, and go find the corresponding controller.

    Second, the controller saves a reference to the parent element in this.element. On the other side, the element saves a reference to the controller instance in jQuery.data.

    $("#foo").data('controllers')

    A helper method called controller (or controllers) using the jQuery.data reference to quickly look up controller instance on any element.

    $("#foo").controller() // returns first controller found
    $("#foo").controllers() // returns an array of all controllers on this element

    Finally, actions are self labeling, meaning if you look at a method called ".foo click", there is no ambiguity about what is going on in that method.

    ### Responding to Actions

    If you name an event with the pattern "selector action", controllers will set these methods up as event handlers with event delegation. Even better, these event handlers will automatically be removed when the controller is destroyed.

    ".todo mouseover" : function( el, ev ) {}

    The el passed as the first argument is the target of the event, and ev is the jQuery event. Each handler is called with "this" set to the controller instance, which you can use to save state.

    ### Removing Controllers

    Part of the magic of controllers is their automatic removal and cleanup. Controllers bind to the special destroy event, which is triggered whenever an element is removed via jQuery. So if you remove an element that contains a controller with el.remove() or a similar method, the controller will remove itself also. All events bound in the controller will automatically clean themselves up.

    ### Defaults

    Controllers can be given a set of default options. Users creating a controller pass in a set of options, which will overwrite the defaults if provided.

    In this example, a default message is provided, but can is overridden in the second example by "hi".

    $.Controller("Message", {
    defaults : {
    message : "Hello World"
    }
    },{
    init : function(){
    this.element.text(this.options.message);
    }
    })

    $("#el1").message(); //writes "Hello World"
    $("#el12").message({message: "hi"}); //writes "hi"

    ### Parameterized Actions

    Controllers provide the ability to set either the selector or action of any event via a customizable option. This makes controllers potentially very flexible. You can create more general purpose event handlers and instantiate them for different situations.

    The following listens to li click for the controller on #clickMe, and "div mouseenter" for the controller on #touchMe.

    $.Controller("Hello", {
    defaults: {item: “li”, helloEvent: “click”}
    }, {
    “{item} {helloEvent}" : function(el, ev){
    alert('hello') el // li, div
    }
    })

    $("#clickMe").hello({item: “li”, helloEvent : "click"});
    $("#touchMe").hello({item: “div”, helloEvent : "mouseenter"});


    ### Pub / Sub

    JavaScriptMVC applications often use OpenAjax event publish and subscribe as a good way to globally notify other application components of some interesting event. The jquery/controller/subscribe method lets you subscribe to (or publish) OpenAjax.hub messages:

    $.Controller("Listener",{
    "something.updated subscribe" : function(called, data){}
    })

    // called elsewhere
    this.publish("some.event", data);

    ### Special Events

    Controllers provide support for many types of special events. Any event that is added to jQuery.event.special and supports bubbling can be listened for in the same way as a DOM event like click.

    $.Controller("MyHistory",{
    "history.pagename subscribe" : function(called, data){
    //called when hash = #pagename
    }
    })

    Drag, drop, hover, and history and some of the more widely used controller events. These events will be discussed later.
    ### $.Controller

    The content for [$.Controller has been moved here](https://gist.github.com/996204).

    ## FuncUnit

  21. JupiterJS revised this gist May 27, 2011. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -183,9 +183,9 @@ Fortunately, JavaScriptMVC makes it easy to make any data observable. A great e
    - limit - the number of items to display
    - count - the total number of items

    We can model this data with JavaScriptMVC like:
    We can model this data with JavaScriptMVC's $.Model like:

    var paginate = new Model({
    var paginate = new $.Model({
    offset: 0,
    limit: 20,
    count: 200
  22. JupiterJS revised this gist May 27, 2011. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    The following is a VERY rough draft of an article I am working on for Alex MacCaw's @maccman's Book. It is very rough, but even now a worthwhile read. Suggestions / comments are very welcome! Please help me :-)

    ## Introduction

    JavaScriptMVC (JMVC) is an open-source jQuery-based JavaScript framework. It is nearly a comprehensive (holistic) front-end development framework; packaging utilities for testing, dependency management, documentation, and a host of useful jQuery plugins. Yet, every part of JavaScriptMVC can be used without every other part, making the library lightweight. It's Class, Model, View, and Controller combined are only 7k minified and compressed, yet even they can be used independently. JavaScriptMVC's independence lets you start small and scale to meet the challenges of the most complex applications on the web.
  23. JupiterJS revised this gist May 27, 2011. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -4,10 +4,10 @@ JavaScriptMVC (JMVC) is an open-source jQuery-based JavaScript framework. It is

    This chapter only covers JavaScriptMVC's $.Class, $.Model, $.View, and $.Controller. JavaScriptMVC's naming conventions deviate slightly from the traditional Model-View-Controller design pattern. The following describes each component:

    - <code>$.Class</code> - a JavaScript based class system.
    - <code>$.Model</code> - a traditional model layer
    - <code>$.View</code> - a client side template system
    - <code>$.Controller</code> - a jQuery plugin system that can serve as traditional controller or view.
    - <code>$.Class</code> - JavaScript based class system.
    - <code>$.Model</code> - traditional model layer
    - <code>$.View</code> - client side template system
    - <code>$.Controller</code> - jQuery plugin system that can serve as traditional controller or view.

    We'll see how $.Controller is used to create traditional view controls, like pagination buttons and list. We'll also learn how to use $.Controller as a traditional controller, one that coordinates between the traditional views and models.

  24. JupiterJS revised this gist May 27, 2011. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -5,7 +5,7 @@ JavaScriptMVC (JMVC) is an open-source jQuery-based JavaScript framework. It is
    This chapter only covers JavaScriptMVC's $.Class, $.Model, $.View, and $.Controller. JavaScriptMVC's naming conventions deviate slightly from the traditional Model-View-Controller design pattern. The following describes each component:

    - <code>$.Class</code> - a JavaScript based class system.
    - <code>$.Model</code> - a traditional model layter
    - <code>$.Model</code> - a traditional model layer
    - <code>$.View</code> - a client side template system
    - <code>$.Controller</code> - a jQuery plugin system that can serve as traditional controller or view.

  25. JupiterJS revised this gist May 27, 2011. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@

    JavaScriptMVC (JMVC) is an open-source jQuery-based JavaScript framework. It is nearly a comprehensive (holistic) front-end development framework; packaging utilities for testing, dependency management, documentation, and a host of useful jQuery plugins. Yet, every part of JavaScriptMVC can be used without every other part, making the library lightweight. It's Class, Model, View, and Controller combined are only 7k minified and compressed, yet even they can be used independently. JavaScriptMVC's independence lets you start small and scale to meet the challenges of the most complex applications on the web.

    This chapter only covers JavaScriptMVC's $.Class, $.Model, $.View, and $.Controller. JavaScriptMVC's naming conventions deviate slightly from the traditional Model-View-Controller design pattern. The following describe each component:
    This chapter only covers JavaScriptMVC's $.Class, $.Model, $.View, and $.Controller. JavaScriptMVC's naming conventions deviate slightly from the traditional Model-View-Controller design pattern. The following describes each component:

    - <code>$.Class</code> - a JavaScript based class system.
    - <code>$.Model</code> - a traditional model layter
  26. JupiterJS revised this gist May 26, 2011. 1 changed file with 23 additions and 75 deletions.
    98 changes: 23 additions & 75 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -547,71 +547,11 @@ Lets say we wanted to know when a task is created and add it to the page. And a

    })



    ### Type Conversion



    ### Events

    Although encapsulating ajax requests in a model is valuable, there's something even more important about models to an MVC architecture - events. $.Model lets you listen model events. You can listen to models being updated, destroyed, or even just having single attributes changed.

    $.Model produces two types of events:

    - OpenAjax.hub events
    - jQuery events

    Each has advantages and disadvantages for particular situations. For now we'll deal with jQuery events.

    ### Getter / Setters ?



    ### Model.Lists

    Often, in complex JS apps, you're dealing with discrete lists of lots of items. For example, you might have two people's todo lists on the page at once.

    Model has the model list plugin to help with this.

    $.Model.List("Todo.List")

    $.Class('ListWidget',{
    init : function(element, username){
    this.element = element;
    this.username = username;
    this.list = new Todo.List();
    this.list.bind("add", this.callback('addTodos') );
    this.list.findAll({username: username});
    this.element.delegate('.create','submit',this.callback('create'))
    },
    addTodos : function(todos){
    // TODO: gets called with multiple todos
    var el = $('<li>').html(todo.name);
    el.appendTo(this.element.find('ul'));
    todo.bind('updated', function(todo){
    el.html(todo.name)
    })
    },
    create : function(ev){
    var self = this;
    new Todo({name: ev.target.name.value,
    username: this.username}).save(function(todo){
    self.list.push(todo);
    })
    }
    });

    new ListWidget($("#briansList"), "brian" );
    new ListWidget($("#justinsList"), "justin" );

    ## $.View - Client Side Templates

    JavaScriptMVC's views are really just client side templates. Later, we'll use $.Controller to create traditional MVC views.
    Client side templates take data and create HTML. They are

    JavaScriptMVC's views are really just client side templates. Client side templates take data and return a string. Typically, the strings are HTML intended to be inserted into the DOM.

    We'll use $.Controller to build jQuery.View is a templating interface that takes care of complexities using templates:
    jQuery.View is a templating interface that takes care of complexities using templates:

    - Convenient and uniform syntax
    - Template loading from html elements and external files.
    @@ -620,24 +560,24 @@ We'll use $.Controller to build jQuery.View is a templating interface that takes
    - Caching of processed templates.
    - Bundling of processed templates in production builds.

    JavaScriptMVC comes pre-packaged with 4 different templates:
    JavaScriptMVC comes pre-packaged with 4 different template engines:

    - EJS
    - JAML
    - Micro
    - Tmpl

    And there are 3rd party plugins for Mustache and Dust.
    This tutorial uses EJS templates, but all the following techniques will work with any template engine with minor syntax difference.

    ### Use
    ### Basic Use

    When using views, you almost always want to insert the results of a rendered template into the page. jQuery.View overwrites the jQuery modifiers so using a view is as easy as:

    $("#foo").html('mytemplate.ejs',{message: 'hello world'})

    This code:

    1. Loads the template a 'mytemplate.ejs'. It might look like:
    1. Loads the template in file 'mytemplate.ejs'. It might look like:

    <h2><%= message %></h2>

    @@ -654,30 +594,38 @@ This code:

    You can use a template with the following jQuery modifier methods:

    $('#bar').after('temp.jaml',{});
    $('#bar').append('temp.jaml',{});
    $('#bar').before('temp.jaml',{});
    $('#bar').html('temp.jaml',{});
    $('#bar').prepend('temp.jaml',{});
    $('#bar').replaceWidth('temp.jaml',{});
    $('#bar').text('temp.jaml',{});
    $('#bar').after('temp.ejs',{});
    $('#bar').append('temp.ejs',{});
    $('#bar').before('temp.ejs',{});
    $('#bar').html('temp.ejs',{});
    $('#bar').prepend('temp.ejs',{});
    $('#bar').replaceWidth('temp.ejs',{});
    $('#bar').text('temp.ejs',{});

    ### Loading from a script tag

    View can load from script tags or from files. To load from a script tag, create a script tag with your template and an id like:

    <script type='text/ejs' id='recipes'>
    <script type='text/ejs' id='recipesEJS'>
    <% for(var i=0; i < recipes.length; i++){ %>
    <li><%=recipes[i].name %></li>
    <%} %>
    </script>

    Render with this template like:

    $("#foo").html('recipes',recipeData)
    $("#foo").html('recipesEJS',recipeData)

    Notice we passed the id of the element we want to render.

    ### Packaging

    StealJS is JavaScriptMVC's dependency management and build system. Although not covered in this book, it's worth noting that StealJS is able to build templates into a production file. This makes the application load much faster as it doesn't have to wait for templates to load.

    ### Deferreds



    ### Asynchronous loading

    By default, retrieving requests is done synchronously. This is fine because StealJS packages view templates with your JS download.
  27. JupiterJS revised this gist May 26, 2011. 1 changed file with 96 additions and 81 deletions.
    177 changes: 96 additions & 81 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -2,9 +2,18 @@

    JavaScriptMVC (JMVC) is an open-source jQuery-based JavaScript framework. It is nearly a comprehensive (holistic) front-end development framework; packaging utilities for testing, dependency management, documentation, and a host of useful jQuery plugins. Yet, every part of JavaScriptMVC can be used without every other part, making the library lightweight. It's Class, Model, View, and Controller combined are only 7k minified and compressed, yet even they can be used independently. JavaScriptMVC's independence lets you start small and scale to meet the challenges of the most complex applications on the web.

    This chapter only covers JavaScriptMVC's $.Class, $.Model, $.View, and $.Controller. JavaScriptMVC's naming conventions deviate slightly from the traditional Model-View-Controller design pattern. The following describe each component:

    - <code>$.Class</code> - a JavaScript based class system.
    - <code>$.Model</code> - a traditional model layter
    - <code>$.View</code> - a client side template system
    - <code>$.Controller</code> - a jQuery plugin system that can serve as traditional controller or view.

    We'll see how $.Controller is used to create traditional view controls, like pagination buttons and list. We'll also learn how to use $.Controller as a traditional controller, one that coordinates between the traditional views and models.

    ## Setup

    This chapter will cover only JavaScriptMVC's Class, Model, Controller, and View. So instead of downloading the entire framework, go to the [download builder](http://javascriptmvc.com/builder.html), check Controller, Model, and View's EJS templates and click download.
    JavaScriptMVC can be used as a single download that includes its entire toolset. But this chapter covers only JavaScriptMVC's MVC parts. Instead of downloading the entire framework, go to the [download builder](http://javascriptmvc.com/builder.html), check Controller, Model, and View's EJS templates and click download.

    The download will come with minified and unminified versions of jQuery and the plugins you selected. Load these with script tags in your page:

    @@ -596,6 +605,92 @@ Model has the model list plugin to help with this.
    new ListWidget($("#briansList"), "brian" );
    new ListWidget($("#justinsList"), "justin" );

    ## $.View - Client Side Templates

    JavaScriptMVC's views are really just client side templates. Later, we'll use $.Controller to create traditional MVC views.
    Client side templates take data and create HTML. They are


    We'll use $.Controller to build jQuery.View is a templating interface that takes care of complexities using templates:

    - Convenient and uniform syntax
    - Template loading from html elements and external files.
    - Synchronous and asynchronous template loading.
    - Template preloading.
    - Caching of processed templates.
    - Bundling of processed templates in production builds.

    JavaScriptMVC comes pre-packaged with 4 different templates:

    - EJS
    - JAML
    - Micro
    - Tmpl

    And there are 3rd party plugins for Mustache and Dust.

    ### Use

    When using views, you almost always want to insert the results of a rendered template into the page. jQuery.View overwrites the jQuery modifiers so using a view is as easy as:

    $("#foo").html('mytemplate.ejs',{message: 'hello world'})

    This code:

    1. Loads the template a 'mytemplate.ejs'. It might look like:

    <h2><%= message %></h2>

    2. Renders it with {message: 'hello world'}, resulting in:

    <h2>hello world</h2>

    3. Inserts the result into the foo element. Foo might look like:

    <div id='foo'><h2>hello world</h2></div>


    ### jQuery Modifiers

    You can use a template with the following jQuery modifier methods:

    $('#bar').after('temp.jaml',{});
    $('#bar').append('temp.jaml',{});
    $('#bar').before('temp.jaml',{});
    $('#bar').html('temp.jaml',{});
    $('#bar').prepend('temp.jaml',{});
    $('#bar').replaceWidth('temp.jaml',{});
    $('#bar').text('temp.jaml',{});

    ### Loading from a script tag

    View can load from script tags or from files. To load from a script tag, create a script tag with your template and an id like:

    <script type='text/ejs' id='recipes'>
    <% for(var i=0; i < recipes.length; i++){ %>
    <li><%=recipes[i].name %></li>
    <%} %>
    </script>

    Render with this template like:

    $("#foo").html('recipes',recipeData)

    Notice we passed the id of the element we want to render.

    ### Asynchronous loading

    By default, retrieving requests is done synchronously. This is fine because StealJS packages view templates with your JS download.

    However, some people might not be using StealJS or want to delay loading templates until necessary. If you have the need, you can provide a callback paramter like:

    $("#foo").html('recipes',recipeData, function(result){
    this.fadeIn()
    });

    The callback function will be called with the result of the rendered template and 'this' will be set to the original jQuery object.


    ## $.Controller - jQuery plugin factory

    JavaScriptMVC's controllers are really a jQuery plugin factory. They can be used as a traditional view, for example, making a slider widget, or a traditional controller, creating view-controllers and binding them to models. If anything happens in your application, a controller should respond to it.
    @@ -727,86 +822,6 @@ Controllers provide support for many types of special events. Any event that is

    Drag, drop, hover, and history and some of the more widely used controller events. These events will be discussed later.

    ## $.View - Client Side Templates

    JavaScriptMVC's views are really just client side templates. jQuery.View is a templating interface that takes care of complexities using templates:

    - Convenient and uniform syntax
    - Template loading from html elements and external files.
    - Synchronous and asynchronous template loading.
    - Template preloading.
    - Caching of processed templates.
    - Bundling of processed templates in production builds.

    JavaScriptMVC comes pre-packaged with 4 different templates:

    - EJS
    - JAML
    - Micro
    - Tmpl

    And there are 3rd party plugins for Mustache and Dust.

    ### Use

    When using views, you almost always want to insert the results of a rendered template into the page. jQuery.View overwrites the jQuery modifiers so using a view is as easy as:

    $("#foo").html('mytemplate.ejs',{message: 'hello world'})

    This code:

    1. Loads the template a 'mytemplate.ejs'. It might look like:

    <h2><%= message %></h2>

    2. Renders it with {message: 'hello world'}, resulting in:

    <h2>hello world</h2>

    3. Inserts the result into the foo element. Foo might look like:

    <div id='foo'><h2>hello world</h2></div>


    ### jQuery Modifiers

    You can use a template with the following jQuery modifier methods:

    $('#bar').after('temp.jaml',{});
    $('#bar').append('temp.jaml',{});
    $('#bar').before('temp.jaml',{});
    $('#bar').html('temp.jaml',{});
    $('#bar').prepend('temp.jaml',{});
    $('#bar').replaceWidth('temp.jaml',{});
    $('#bar').text('temp.jaml',{});

    ### Loading from a script tag

    View can load from script tags or from files. To load from a script tag, create a script tag with your template and an id like:

    <script type='text/ejs' id='recipes'>
    <% for(var i=0; i < recipes.length; i++){ %>
    <li><%=recipes[i].name %></li>
    <%} %>
    </script>

    Render with this template like:

    $("#foo").html('recipes',recipeData)

    Notice we passed the id of the element we want to render.

    ### Asynchronous loading

    By default, retrieving requests is done synchronously. This is fine because StealJS packages view templates with your JS download.

    However, some people might not be using StealJS or want to delay loading templates until necessary. If you have the need, you can provide a callback paramter like:

    $("#foo").html('recipes',recipeData, function(result){
    this.fadeIn()
    });

    The callback function will be called with the result of the rendered template and 'this' will be set to the original jQuery object.

    ## FuncUnit

  28. JupiterJS revised this gist May 26, 2011. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -21,7 +21,7 @@ JMVC's Controller and Model are based on it's Class helper - $.Class. To create
    }
    });

    In the example above, instances of Animal have a <code>breathd()</code> method. We can create a new <code>Animal</code> instance and call <code>breathe()</code> on it like:
    In the example above, instances of Animal have a <code>breath()</code> method. We can create a new <code>Animal</code> instance and call <code>breathe()</code> on it like:

    var man = new Animal();
    man.breathe();
  29. JupiterJS revised this gist May 26, 2011. 1 changed file with 26 additions and 0 deletions.
    26 changes: 26 additions & 0 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -494,6 +494,32 @@ The following table details how to use the task model to CRUD tasks.

    The <code>Task</code> model has essentially become a contract to our services!

    ### Type Conversion

    Did you notice how the server responded with createdAt values as numbers like <code>1303173531164</code>. This number is actually April 18th, 2011. Instead of getting a number back from <code>task.createAt</code>, it would be much more useful if it returns a JavaScript date created with <code>new Date(1303173531164)</code>. We could do this with a <code>setCreatedAt</code> setter. But, if we have lots of date types, this will quickly get repetitive.

    To make this easy, $.Model lets you define the type of an attribute and a converter function for those types. Set the type of attributes on the static <code>attributes</code> object and converter methods on the static <code>convert</code> object.

    $.Model('Task',{
    attributes : {
    createdAt : 'date'
    },
    convert : {
    date : function(date){
    return typeof date == 'number' ? new Date(date) : date;
    }
    }
    },{});

    Task now converts createdAt to a Date type. To list the year of each task, write:

    Task.findAll({}, function(tasks){
    $.each(tasks, function(){
    console.log( "Year = "+this.createdAt.fullYear() )
    })
    });


    ### CRUD Events

    Model publishes events when an instance has been created, updated, or destroyed. You can listen to these events globally on the Model or on an individual model instance. Use <code>MODEL.bind(EVENT, callback( ev, instance ) )</code> to listen for created, updated, or destroyed events.
  30. JupiterJS revised this gist May 26, 2011. 1 changed file with 50 additions and 123 deletions.
    173 changes: 50 additions & 123 deletions JavaScriptMVC.md
    Original file line number Diff line number Diff line change
    @@ -274,21 +274,46 @@ Now the nextPrev plugin can set offset with reckless abandon:
    paginate.attr('offset', paginate.offset-paginate.limit );
    });

    But the Paginate model can make it event easier to move to the next and previous page and know if it's possible by adding helper methods.
    ### Defaults

    We can add default values to Paginate instances by setting the static defaults property object that contains the default attributes. When a new paginate instance is created, if no value is provided, it will use the default value.

    $.Model('Paginate',{
    defaults : {
    count: Infinity,
    offset: 0,
    limit: 100
    }
    },{
    setCount : function(newCount, success, error){ ... },
    setOffset : function(newOffset, success, error){ ... }
    })

    var paginate = new Paginate();
    assertEqual(paginate.limit, 100);


    This is getting sexu, but the Paginate model can make it event easier to move to the next and previous page and know if it's possible by adding helper methods.

    ### Helper methods

    Helper methods are prototype methods that help set or get useful data on model instances.
    Helper methods are prototype methods that help set or get useful data on model instances. The following, completed, Paginate model includes a <code>next</code> and <code>prev</code> method that will move to the next and previous page if possible. It also provides a <code>canNext</code> and <code>canPrev</code> method that returns if the instance can move to the next page or not.

    $.Model('Paginate',{
    setCount : function(newCount, success, error){
    return newCount < 0 ? 0 : newCount;
    defaults : {
    count: Infinity,
    offset: 0,
    limit: 100
    }
    },{
    setCount : function( newCount ){
    return Math.max(0, newCount );
    },
    setOffset : function(newOffset, success, error){
    return newOffset < 0 ? 0 : Math.min(newOffset, !isNaN(this.count - 1) ? this.count : Infinity )
    setOffset : function( newOffset ){
    return Math.max( 0 , Math.min(newOffset, this.count ) )
    },
    next : function(){
    this.attr('offset', paginate.offset+paginate.limit);
    this.attr('offset', this.offset+this.limit);
    },
    prev : function(){
    this.attr('offset', this.offset - this.limit )
    @@ -297,11 +322,11 @@ Helper methods are prototype methods that help set or get useful data on model i
    return this.offset > this.count - this.limit
    },
    canPrev : function(){
    return this.offset === 0
    return this.offset > 0
    }
    })

    The jQuery widget becomes much more refined:
    Thus jQuery widget becomes much more refined:

    $.fn.nextPrev = function(paginate){
    this.delegate('.next','click', function(){
    @@ -467,119 +492,31 @@ The following table details how to use the task model to CRUD tasks.
    </tr>
    </table>

    The <code>Task</code> model has essentially become a contract to our services!

    ### Create tasks on the server by posting the task's data to <code>/tasks.json</code> with:

    new Task({ name: 'take out trash'}).save();

    Retrieve a single task from the server with:

    Task.findOne({id: 5}, function(task){ })

    Retrieve lists of tasks from the server with:

    Task.findAll({id: 5}, function(task){ })

    Update a task by changing it's attributes and calling <code>save</code>:

    task.attr('name', 'Take out the trash now');
    task.save();

    Delete a task with:

    task.destroy();





    Assuming '/tasks.json' returns a JSON array like ...

    [{
    "id" : 1,
    "name" : "take out trash",
    "acl" : "rw",
    "createdAt": 1303000731164 // April 16 2011
    },
    {
    "id" : 2,
    "name" : "do the dishes",
    "acl" : "r" ,
    "createdAt": 1303087131164 // April 17 2011
    }]

    ... the following will retrieve all tasks from the server and then destroy tasks that the user is able to destroy:
    ### CRUD Events

    Task.findAll({}, function(tasks){
    for(var i =0; i < tasks.length; i++){
    Model publishes events when an instance has been created, updated, or destroyed. You can listen to these events globally on the Model or on an individual model instance. Use <code>MODEL.bind(EVENT, callback( ev, instance ) )</code> to listen for created, updated, or destroyed events.

    var task = tasks[i];
    Lets say we wanted to know when a task is created and add it to the page. And after it's been added to the page, we'll listen for updates on that task to make sure we are showing its name correctly. We can do that like:

    if( task.canDestroy() ){
    task.destroy();
    }
    }
    });




    For example, take a todos service that allowed you to create, retrieve, update and delete todos like:

    POST /todos name=laundry dueDate=1300001272986 -> {'id': 8}
    GET /todos -> [{'id': 5, 'name': "take out trash", 'dueDate' : 1299916158482},
    {'id': 7, 'name': "wash dishes", 'dueDate' : 1299996222986},
    ... ]
    GET /todos/5 -> {'id': 5, 'name': "take out trash", 'dueDate' : 1299916158482}
    PUT /todos/5 name=take out recycling -> {}
    DELETE /todos/5 -> {}

    Making a Model that can connect to these services and add helper functions is shockingly easy:

    $.Model("Task",{
    findAll : "GET /tasks.json",
    findOne : "GET /tasks/{id}.json",
    create : "POST /tasks.json",
    update : "PUT /tasks/{id}.json",
    destroy : "DELETE /tasks/{id}.json"
    },{
    canDestroy : function(){
    return this.acl.indexOf('w') > -1
    }
    });

    This allows you to
    Task.bind('created', function(ev, task){
    var el = $('<li>').html(todo.name);
    el.appendTo($('#todos'));
    task.bind('updated', function(){
    el.html(this.name)
    }).bind('destroyed', function(){
    el.remove()
    })

    // List all todos
    Todo.findAll({}, function(todos){
    var html = [];
    for(var i =0; i < todos.length; i++){
    html.push(todos[i].name+" is due in "+
    todos[i].daysRemaining()+
    "days")
    }
    $('#todos').html("<li>"+todos.join("</li><li>")+"</li>")
    })

    //Create a todo
    new Todo({
    name: "vacuum stairs",
    dueDate: new Date()+86400000
    }).save(function(todo){
    alert('you have to '+todo.name+".")
    });

    //update a todo
    todo.update({name: "vacuum all carpets"}, function(todo){
    alert('updated todo to '+todo.name+'.')
    });

    //destroy a todo
    todo.destroy(function(todo){
    alert('you no longer have to '+todo.name+'.')
    });
    ### Type Conversion


    Of course, you can supply your own functions.

    ### Events

    @@ -590,17 +527,7 @@ $.Model produces two types of events:
    - OpenAjax.hub events
    - jQuery events

    Each has advantages and disadvantages for particular situations. For now we'll deal with jQuery events. Lets say we wanted to know when a todo is created and add it to the page. And after it's been added to the page, we'll listen for updates on that todo to make sure we are showing its name correctly. We can do that like:

    $(Todo).bind('created', function(todo){
    var el = $('<li>').html(todo.name);
    el.appendTo($('#todos'));
    todo.bind('updated', function(todo){
    el.html(todo.name)
    }).bind('destroyed', function(){
    el.remove()
    })
    })
    Each has advantages and disadvantages for particular situations. For now we'll deal with jQuery events.

    ### Getter / Setters ?