< documentation

Getting Started 1.0.x


creating a new project

To follow along with this step create this folder structure with a couple javascript files:

                
              
      
    
      
              
                /*  example project  */
 \example
     \app
         \boot
           - client.js
         \configs
           - config.js
     \lib
       - jquery.js
       - jquery.claypool.js
 - index.html

                
              
      
  
    
            
              


  • scanning

    Scanning is a railable pattern that allows you to setup a project with as little configuration as possible, and as you progress, it saves you some of the redundency of configuration by making use of some simple conventions. The following shows all the configuration we need to get going.

                        
                      
              
        
              
                      
                        /**   config.js   **/
    
    var Example = &#x7B;
        Models:&#x7B;},
        Views:&#x7B;},
        Controllers:&#x7B;}
    };
    
    (function($)&#x7B;
    
       $.scan([
            "Example.Models", 
            "Example.Views", 
            "Example.Controllers"
        ]);
        
    })(jQuery);
    
                        
                      
              
      
            
                    
                      
    This simply lets jquery-claypool know where it will eventually look in the global namespace to find your application event handlers etc. The 'Example' object literal is basically how we'll organize and identify our application specific code. All you need to know for now is that claypool is lazy, and lets you be lazy too.


  • boot strapping

    Booting the application should be wrapped in the usual jquery ready. We'll revisit the boot process a little later but for the purposes of our little intro, this is good enough to get us going.

                        
                      
              
        
              
                      
                        /**   client.js   **/
    
    jQuery.noConflict();
    (function($)&#x7B;
        
        $(document).ready(function()&#x7B;
            $.boot();
        });    
        
    })(jQuery);  
    
    
                        
                      
              
      
            
                    
                      
    At this point we can actually check that our app is working. It won't do anything but that's ok! We didn't really talk about the html but in case you need it, up to now it'll look like this:
                        
                      
              
        
              
                      
                        /**   index.html   **/
    
    <html xmlns="http://www.w3.org/1999/xhtml">
        <head>
            <title>First jQuery-Claypool App</title>
            
            <script src="lib/jquery.js"            type="text/javascript"></script>
            <script src="lib/jquery.claypool.js"   type="text/javascript"></script>
            <script src="app/configs/config.js"    type="text/javascript"></script> 
            <script src="app/boot/client"          type="text/javascript"></script> 
        
        </head>
        <body>
            <div>Hello World!</div>
        </body>
    </html>
    
    
                        
                      
              
      
            
                    
                      
    Note: so far everything we've done is the same whether we are going to run this application on the client or on the server.

adding a route

Routes are basically where we return to each time we want to add a feature. It's also the first place you'll look when you want to find out where you need to look to find something in your application code. Routers are a common framework pattern to provide a consistent layer of delegation and a clear mapping of events to application controllers.


  • basic paginator

    To get started we just need to decide on a feature. For this example we are going to add a 'paginator', which is really just a list of links.
    Here our html:

                        
                      
              
        
              
                      
                         /** pagination markup **/
    <div id='pages'>
        <a href='#example/page/1'>1</a> | 
        <a href='#example/page/2'>2</a> | 
        <a href='#example/page/3'>3</a> | 
        <a href='#example/page/4'>4</a> | 
        <a href='#example/page/5'>5</a>  
    </div>
    
                        
                      
              
         
      
            
                    
                      
    Now we need to create the file we will use, by convention, to store all of our application event bindings. This is called app/config/routes.js .
                        
                      
              
        
              
                      
                        /*  example project  */
     \example
         \app
             \configs
               - routes.js
    
                        
                      
              
      
            
                    
                      
    And here is our first router :
                        
                      
              
        
              
                      
                         /** routes.js **/
    (function($)&#x7B;
       
       $.mvc(&#x7B;
            "hijax:a" : [&#x7B;
                id:"#example-hash-routes",
                active:false,
                filter:"[href*=#example]",
                hijaxMap:
                   [&#x7B;urls:"page/|:id|$",   controller:"#pagesController"}]
            }]
        });
        
    })(jQuery);
    
                        
                      
              
         
      
            
                    
                      
    You'll evetually be able to read routers like a book, but for now this one loosely translates to Capture all clicks of links whose href starts with '#example' and send the ones that end with 'page/abc123' to the event handler known as '#pageController'. Of course we need to write that controller still, so let's do that next.

lazy event handling

As we create our first simple event handler, try to keep a couple key concepts in mind.

  1. First, it looks like a normal event handler, uses simple prototype patterns, but has its own closure. The closure will come in handy very soon aside from it's basic ability to provide shorthand names for jQuery and Example.Controllers ($ and $C respectively).
  2. Second, notice that we never create an instance of the event handler. jquery-claypool will create a single instance the first time the event needs to be routed to that controller, and will reuse that instance thereafter.


  • writing your first event handler

    You are about to create your first application event handler, or controller . First we need a new folder and file. (Don't forget to add the additional script tag to your index.html)

                        
                      
              
        
              
                      
                        /*  example project  */
     \example
         \app
             \controllers
               - pages.js
    
                        
                      
              
      
            
                    
                      
    And here is our controller:
                        
                      
              
        
              
                      
                        /*  pages.js  */
    (function($, $C)&#x7B;
        
        
        $C.Pages = function(options)&#x7B;
            $.extend(true, this, options);
        };
        
        $.extend($C.Pages.prototype, &#x7B;
            handle:function(event)&#x7B;
                var id = event.params('id');
                alert('page '+id);
            }
        });
        
    })(jQuery, Example.Controllers);
    
                        
                      
              
      
            
                    
                      

    And now when you reload your page you should be able to click on any of the numbered links we just added and get an alert message displaying the number you just clicked on. We'll talk more later about regular expressions in routes and how those become event params.

adding some logging

Adding alerts to event handlers to see if they are getting triggered correctly is about as useful long-term as adding console.log statements that you comment in and out everytime you want to see the event in your console.

A much better approach is 'instrumented logging' which allows you to leave the log statements in your code, and turn them on or off from a single external location. As you start adding features to projects and accidently break some old feature, you will find it much faster to just turn up logging for a moment to see where the flow breaks, instead of walking through the code in a debugger. You may still need a debugger eventually, but isolating where something is breaking is much faster with category logging.


  • keeping it private

    It's actually very easy to add logging and we are already going to take advantage of that closure we created for our event handler, aka our first controller. We are simply going to use the very common privacy pattern:

                        
                      
              
        
              
                      
                        /*  pages.js a la logging  */
    (function($, $C)&#x7B;
        
        var log;
        
        $C.Pages = function(options)&#x7B;
            $.extend(true, this, options);
            log = $.logger('Example.Controllers.Pages');
        };
        
        $.extend($C.Pages.prototype, &#x7B;
            handle:function(event)&#x7B;
                var id = event.params('id');
                log.debug('got page %s', id);
            }
        });
        
    })(jQuery, Example.Controllers);
    
                        
                      
              
      
            
                    
                      
    All we did was declare a var 'log' at the top of the anonymous scope, and then initialized the variable inside the controllers constructor. This means only this controller will ever have access to it's logger.

    For now just go with the idea that a logger is created with $.logger using the name of the class it belongs to.

    Also notice we replace the alert in the event handler and use a sprintf-style message. This prevents logging statements from ever being constructed when logging is turned off (more on that in the intermediate guide) so leaving the logging in your code has near-zero net impact on performance.


  • tuning the instrumentation

    before we actually get any messages from the logging system, we have to turn it on. To do this we'll create a file just for logging configuration so we always know where to look for it. (Don't forget to include this new file to your index.html)

                        
                      
              
        
              
                      
                        /*  example project  */
     \example
         \app
             \configs
               - logging.js
    
                        
                      
              
      
            
                    
                      
    And now here is what we'll put in that file:
                        
                      
              
        
              
                      
                         /** logging.js **/
    (function($)&#x7B;
       
       $.logging([
            &#x7B; category:"Example",               level:"INFO" },
            &#x7B; category:"Example.Models",        level:"DEBUG" },
            &#x7B; category:"Example.Views",         level:"DEBUG" },
            &#x7B; category:"Example.Controllers",   level:"DEBUG" },
            &#x7B; category:"Claypool",              level:"INFO"  },
            &#x7B; category:"Claypool.MVC",          level:"INFO" },
            &#x7B; category:"root",                  level:"WARN"  }
        ]);
        
    })(jQuery);
    
                        
                      
              
         
      
            
                    
                      
    Logging categories are hierarchical, and the 'root' category is a special catch-all. Basically if a logger is created with a category name Example.Controllers.Pages, but no exact match is configured, it will use the closest match, in this case, 'Example.Controllers'.

    You should now be able to open up your firebug console and see the messages. Dont be surprised if you see more, jquery-claypool is fully instrumented with logging too, so you can peer under the hood when you need or want too. Note, this is all true for server-side jquery-claypool as well, but messages are written to the server logs.

updating the page

The primary role of the controller is to create a basket of state, sometimes modifying it in the process. Like any event handler it may get some of that state from the event itself, use ajax (via a 'model') or inspect the dom.

The 'view' is where we draw a little line in the sand, and pass all that information we gathered in the controller over the fence. The controller doesn't care what is done with that infomation, and likewise the view doesn't care how the controller got the data. The views job is to simply make use of the data to update the page as the end user sees it.


  • some loremipsum

    To get us started on rendering something useful we're going to 'fake' some information (don't forget to include it in your index.html). Here is how we will modify our pages controller

                        
                      
              
        
              
                      
                        /* controllers/pages.js */
    (function($, $C)&#x7B;
        
        var log;
        
        $C.Pages = function(options)&#x7B;
            $.extend(true, this, options);
            log = $.logger('Example.Controllers.Pages');
        };
        
        $.extend($C.Pages.prototype, &#x7B;
            handle:function(event)&#x7B;
                var id = event.params('id');
                log.debug('got id %s', id);
                event.m(&#x7B;
                    index:id,
                    title:$.titled(3, false),
                    description:$.paragraphs(3, false).join('\n')
                }).render();
            }
        });
        
    })(jQuery, Example.Controllers);
    
                        
                      
              
      
            
                    
                      
    With that, we are ready to create our first view.


  • a point of view

    Views and Controllers are, generally, closely related, and that relationship is analogous to a Client and Server relationship. The server exposes data to the client, what the client does with it is of little concern to the server. Likewise the controller doesnt concern itself with what the view does.

    We'll need to create a new file for our first view. (Don't forget to include this new file to your index.html)

                        
                      
              
        
              
                      
                        /*  example project  */
     \example
         \app
             \views
               - pages.js
    
                        
                      
              
      
            
                    
                      
    And here is our new markup:
                        
                      
              
        
              
                      
                         /** pagination markup **/
    <body>
        <div>Hello World!</div>
        <div id='pages'>
            <a href='#example/page/1'>1</a> | 
            <a href='#example/page/2'>2</a> | 
            <a href='#example/page/3'>3</a> | 
            <a href='#example/page/4'>4</a> | 
            <a href='#example/page/5'>5</a>
            <h2 id='title'>title</h2> 
            <h4>Page (<span id='index'>?</span>)</h4>
            <p id='description'>
                description
            </p>
        </div>
    </body>
    
                        
                      
              
         
      
            
                    
                      
    Finally here is a simple view that uses some jQuery dhtml magic to update the screen:
                        
                      
              
        
              
                      
                        /*  views/pages.js  */
    (function($, $V)&#x7B;
        
        var log;
        
        $V.Pages = function(options)&#x7B;
            $.extend(true, this, options);
            log = $.logger('Example.Views.Pages');
        };
        
        $.extend($V.Pages.prototype, &#x7B;
            update:function(model)&#x7B;
                log.debug('updating page %s', model.index);
                $('#index').text(model.index);
                $('#title', this).text(model.title);
                $('#description', this).text(model.description);
            }
        });
        
    })(jQuery, Example.Views);
    
                        
                      
              
      
            
                    
                      
    Note that when we use use the jQuery function $() we provide a context object in several cases, eg $(selector, this). We can do this because jquery-claypool will automatically bind the view to an element with the same id if it exists (eg Views.Pages -> #pages).

gathering data

In this step we will use some simple AJAX routines to load data for our app.

In larger apps it tends to be very helpful to consolidate your AJAX routines to an object usually refered to as a Model . The Model just provides a convenient place to isolate validatation routines, and network abstractions for retreiving data from the server or some restful network storage.


  • just ajax

    We'll need to create a new file for our first view. (Don't forget to include this new file to your index.html)

                        
                      
              
        
              
                      
                        /*  example project  */
     \example
         \app
             \models
               - pages.js
    
                        
                      
              
      
            
                    
                      
    Here is our Model which retreives 'pages' in a json format from the server.
                        
                      
              
        
              
                      
                        /* models/pages.js*/           
    (function($, $M)&#x7B;
        
        var log;
        
        $M.Pages = function(options)&#x7B;
            $.extend(true, this, options);
            log = $.logger('Example.Models.Pages');
        };
        
        $.extend($M.Pages.prototype, &#x7B;
            get:function(id, options)&#x7B;
                log.debug('getting page %s', id);
                    $.ajax(&#x7B;
                        url:'./data/'+id+'.json',
                        dataType:'json',
                        success:function(page)&#x7B;
                            log.debug('got page %s', id);
                            if(options && options.success )&#x7B;
                                options.success(page);
                            }
                        }
                    });
                }
                return this;
            }
        });
        
    })(jQuery, Example.Models);
    
                        
                      
              
      
            
                    
                      
    And we can replace the lorem ipsum now in our controller:
                        
                      
              
        
              
                      
                        /* controllers/pages.js */
    
    (function($, $C)&#x7B;
        
        var log,
            Pages;
        
        $C.Pages = function(options)&#x7B;
            $.extend(true, this, options);
            log = $.logger('Example.Controllers.Pages');
            Pages = $.$('#pagesModel');
        };
        
        $.extend($C.Pages.prototype, &#x7B;
            handle:function(event)&#x7B;
                var id = event.params('id');
                log.debug('got id %s', id);
                Pages.get(id,&#x7B;
                    success: function(page)&#x7B;
                        event.m(&#x7B;
                            index:id,
                            title:page.title,
                            description:page.description
                        }).render();
                    }
                });
                   
            }
        });
        
    })(jQuery, Example.Controllers);
    
    
                        
                      
              
      
            
                    
                      
    One thing you may have noticed was the jQuery plugin method $.$, or jQuery.$, this is one of the most powerful tools jquery-claypool provides as a framework tool, and it is used internally as well as provided to the end-user. Any application managed instance is available via $.$, and if it hasn't been created yet jquery-claypool creates it for you.


  • cache only

    Without getting fancy we are going to demonstrate one reason it's nice to seperate the model. Without modifying the controller which uses the model, we can add a simple caching mechanism so we don't repeat AJAX calls we don't have too.

                        
                      
              
        
              
                      
                        /* models/pages.js */
    
    (function($, $M)&#x7B;
        
        var log,
            cache;
        
        $M.Pages = function(options)&#x7B;
            $.extend(true, this, options);
            log = $.logger('Example.Models.Pages');
            cache = &#x7B;};
        };
        
        $.extend($M.Pages.prototype, &#x7B;
            get:function(id, options)&#x7B;
                log.debug('getting page %s', id);
                if(!cache[id])&#x7B;
                    $.ajax(&#x7B;
                        url:'./data/'+id+'.json',
                        dataType:'json',
                        success:function(page)&#x7B;
                            log.debug('got page %s', id);
                            cache[id] = page;
                            if(options && options.success )&#x7B;
                                options.success(page);
                            }
                        },
                        error:function(xhr,status,e)&#x7B;
                            log.error('error getting page %s', id).
                                exception(e);
                            if(options && options.error)&#x7B;
                                options.error(&#x7B;
                                    status: status,
                                    msg: 'network error'+e
                                });
                            }
                        }
                    });
                }else&#x7B;
                    log.debug('got cached page %s', id);
                    if(options && options.success)&#x7B;
                        options.success(cache[id]);
                    }
                }
                return this;
            }
        });
        
    })(jQuery, Example.Models);
    
                        
                      
              
      
            
                    
                      

working well with others

jQuery-Claypool provides a very simple and powerful framework for managing environments. Environments are defined and used in order to isolate all application specific settings that may vary depending on where the application is being used. Common examples include development, testing, QA, and production environments.


  • defining environments

    We'll need to create a new file for our first view. (Don't forget to include this new file in your index.html)

                        
                      
              
        
              
                      
                        /*  example project  */
     \example
         \app
             \configs
               - environments.js
    
                        
                      
              
      
            
                    
                      
    For the purposes of our example we are going to assume that the url for accessing our data may vary across environments so we will create a setting for it. Here is the contents of environments.js:
                        
                      
              
        
              
                      
                        /*  configs/environments.js  */
    
    (function($)&#x7B; 
        
       $.env(&#x7B;
            defaults:&#x7B;
                version:'0.0.0'
            },
            dev:&#x7B;
                client:&#x7B;
                    pages:'/apps/tutorial/5/data/'
                }
            },
            test:&#x7B;
                client:&#x7B;
                    pages:'/jquery-claypool/apps/tutorial/5/data/'
                }    
            },
            qa:&#x7B;
                client:&#x7B;
                    pages:'/jquery-claypool-qa/apps/tutorial/5/data/'
                }
            },
            prod:&#x7B;
                client:&#x7B;
                    pages:'/data/'
                }
            }
        });     
        
    })(jQuery);
        
    
                        
                      
              
      
            
                    
                      


  • selecting environments

    All we need to do now to take advantage of our environmental settings is choose one. Changing environments should allows only require a one line change in one file.

                        
                      
              
        
              
                      
                        /* boot/client.js */
    
    jQuery.noConflict();
    (function($)&#x7B;
        
        //A static logger for any initialization routines we might add here
        var log = $.logger("Example");
        
        //The environments are described in environments.js
        try&#x7B;
           $.env('defaults', "dev.client");
        }catch(e)&#x7B;
           log.error("Environmental selection is invalid!").exception(e);
        }
        
        $(document).ready(function()&#x7B;
            $.boot();
        });    
        
    })(jQuery);  
    
    
                        
                      
              
      
            
                    
                      
    And finally our model can be updated to take advantage of the new flexibility granted to us via environments. Note our url property of the $.ajax call uses $.env to access the new setting without any knowledge of which environment was selected at boot time.
                        
                      
              
        
              
                      
                        /* models/pages.js */
    
    (function($, $M)&#x7B;
        
        var log,
            cache;
        
        $M.Pages = function(options)&#x7B;
            $.extend(true, this, options);
            log = $.logger('Example.Models.Pages');
            cache = &#x7B;};
        };
        
        $.extend($M.Pages.prototype, &#x7B;
            get:function(id, options)&#x7B;
                log.debug('getting page %s', id);
                if(!cache[id])&#x7B;
                    $.ajax(&#x7B;
                        url:$.env('pages')+id+'.json',
                        dataType:'json',
                        success:function(page)&#x7B;
                            log.debug('got page %s', id);
                            cache[id] = page;
                            if(options && options.success )&#x7B;
                                options.success(page);
                            }
                        },
                        error:function(xhr,status,e)&#x7B;
                            log.error('error getting page %s', id).
                                exception(e);
                            if(options && options.error)&#x7B;
                                options.error(&#x7B;
                                    status: status,
                                    msg: 'network error'+e
                                });
                            }
                        }
                    });
                }else&#x7B;
                    log.debug('got cached page %s', id);
                    if(options && options.success)&#x7B;
                        options.success(cache[id]);
                    }
                }
                return this;
            }
        });
        
    })(jQuery, Example.Models);
    
                        
                      
              
      
            
                    
                      

whats next

So far we've covered some high level concepts and that should be enough to get you started. There is much more to learn though so your project can take advantage of every feature you need without reinventing it.


  • intermediate topics

    Intermediate topics include:

    • Route your heart out
    • Re: Modeling
    • Template technologies.
    • Control Flow with event.m().v().c()
    • Application Filters
    • Services are Server-Side Event Handlers


  • advanced topics

    Advanced topics include:

    • Writing Routers
    • Backending to SDB
    • Deploying to the Cloud
    • Recycling, or Javascript in the Ether
    • Framework Extension Points
    • Inversion of Control
    • The Claypool Proxy Server

Getting Started releases

Plugins

Extension Points

This guide is applicable to both the jquery-claypool client and server application frameworks. Where the two differ functionally the documentation will provide notes and examples of usage in each environment.