JMVC + JQM improved dispatch
In my previous example, I used an eval to load a page controller from the jQuery.fn name space. Here is a much better version of that code which has the added benefit of allowing access to the instance of my controller:
If ( typeof MyApp.Pages[pageName] === 'function') { // don't really need the element passed here per this example's controller, will check if needed. pageInstance = new MyApp.Pages[pageName]($('body')); pageInstance.view.done( function ( htmlOutput ) { $('body').append(htmlOutput); $('#' + pageName).page(); $.mobile.changePage( $('#' + pageName) ); }
On the controller side, the init method becomes much simpler than I had originally written:
/** * @class MyApp.Pages.Frontpage */ $.Controller('MyApp.Pages.Frontpage', /** @Static */ { defaults : { itemsPerPage : 20, currentPage : 1 }, pluginName: 'frontpage' }, /** @Prototype */ { /** * Downloads and renders a full page of blog posts */ init : function() { this.view = $.View("my_app/pages/views/frontpage.ejs", { items: MyApp.Models.BlogPost.findAll({ start : (this.options.currentPage-1) * this.options.itemsPerPage, count : this.options.itemsPerPage }) }); } } ); // End of controller
My full bootstrap method now looks like this:
function() { // intercept changePage events to inject our controllers as needed (dispatch) $(document).bind( "pagebeforechange", function( e, data ) { // we only handle url changes if ( typeof data.toPage === "string" ) { // We are being asked to load a page by URL var u = $.mobile.path.parseUrl( data.toPage ), re = /^\#([a-zA-Z]+)$/; // TODO $.route if (u.hash.search(re) !== -1 && $(u.hash).length == 0) { var pageName = re.exec(u.hash); pageName = pageName[1]; if(pageName === 'splah') { return false; } // ucwords - ignore as it will be replaced by using $.route controllerName = pageName.replace(/^([a-z])|\s+([a-z])/g, function (str) { return str.toUpperCase(); }); if (typeof MyApp.Pages[controllerName] === 'function') { var $instance = new MyApp.Pages[controllerName]($('body')); $instance.view.done(function (htmlOutput){ // add the rendered output to the body (could also be done in the controllers instead) $('body').append(htmlOutput); $('#' + pageName).page(); // jQuery Mobile magic decoration // passing an object skips the dispatch and just shows the page $.mobile.changePage($('#' + pageName)); }); e.preventDefault(); } } } }); $('#splash').fadeIn(500); setTimeout(function () { $.mobile.changePage('#frontpage'); }, 500); });
I’ll flesh out the full updated integration when I get home, but i am now close to my ideal setup and my full app is working as expected from start to finish. Among my recent changes are the use of partials, routes, pagination, API service auth (with caveats) and of course testing and documentation.
Stay tuned!