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:
1 2 3 4 5 6 7 8 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | /** * @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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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!
Johannes Neugschwentner
/ February 19, 2012lovely! hope this and the previous posts get me started, haven’t looked for longer then 2 or 3 hours now, but this is the sweetest I found so far
It also possibly gives me a hint as to my little prob with jqm-multipages —- http://stackoverflow.com/questions/9151351/jquerymobile-woes-1-0-1-not-working-properly-in-eclipse-adt-android-simula
—-
(I think the magic jqm command “page()” could do the trick)
Christian Moelders
/ April 20, 2012I agree with Johannes, it is a great approach!
Unfortunately I am in trouble with the routes. Similar to you I want to use $.route to get the right page controllers. However, when I steal “jquery/controller/route” and the app calls $.mobile.changePage($(‘#’ + pageName)); in the “pagebeforechange”-callback,
it triggers a new “pagebeforechange”-event caused by the new hash-value. Therefore the requested page will be replaced again.
Any hints on what I’m doing wrong?
Tzu
/ May 18, 2012Very nice guide you are building here, keep up the good work!