fredagen den 18:e mars 2011

jQuery Mobile , MVC3 and Razor View Engine,JavaScripts and AJAX loading.

The latest two weeks I have been given the opportunity to do some development upon the jQuery Mobile framework, Microsoft MVC3 and Razor (View Engine) plus our WebSocket Server and I must say it has been a wonderful journey.  During an early stage in the project I run into some minor problems , I want to share this with you, and the solution we came up with, hopefully it can give you something, or maybe create a bit of feedback that we can use?
I have put together a sample Web App , chosen Razor as the MVC View Engine and to use a layout page (ASPX synonym for layout page is master page). As we target the web app to run on mobile devices such as iPhone and  Android.
The web consists of three very simple views ; Home, About and Sample, which all rely of the layout page (master) .
As jQuery Mobile includes a very useful and powerful mechanism for automatic AJAX of pages with back history support , animated page transitions and events related to those pages we need to understand the anatomy of those page.
The page structure of jQuery Mobile starts with a HTML5 doctype, further on references to jQuery, jQuery Mobile and css files, as well as custom JavaScripts (yours).

jQuery Mobile brings a rich, native-like experience that can't be achieved with standard HTTP requests.
In our case we noticed that we in an early stage the amount of scripts grow rapidly.

Razor Layout page

The layout page _Layout.cshtml of mine looks like (also see Mobile page structure at jQM )
<!DOCTYPE html>
<html>
<head>
   
<title>@ViewBag.Title</title>
   
<link href="/Content/jquery.mobile-1.0a3.min.css" rel="stylesheet" type="text/css" />
    <
script src="/Scripts/jquery-1.5.1.js" type="text/javascript"></script>
   
<script src="/Scripts/jquery.mobile-1.0a3.min.js" type="text/javascript"></script>
   
<script src="/Scripts/Views/Shared/_layout.js" type="text/javascript"></script>
    
</head>
<body>
    @RenderBody()
</body>
</html>
The last script resource of mine pointing to /scripts/Views/Shared/_layout.js reflects to structure of out MVC3 Application (/Views/Shared/ ) where the layout page is located .
As “pages” as AJAX fetched and inserted into the into the DOM we cant put “JavaScript” into those as we are used to therefore we run into a problem; The amount scripts code will down us, as well as the maintenance could be an issue in the future?
The events of jQuery Mobile is impressive

Page Initialization

Page Initialization events brings you the possibility to manipulate the “page” either pre-or-post the initialization, this events will only fire once per “page”.
pagebeforecreate is triggered when the page is being initialized and before the initialization, pagecreate triggers on the page being initialized and after initalization.
This is very useful, by using those events we can load JavaScript resources bound the the “page” being created , this is our solution of the problem.
Before we look at how we uses those events to solve our problem we need to go back to the anatomy of the jQM page.
Inside the “page” (Razor View ) we added a <div> tag with the data-role=”page” , this is an immediate children of the page among with other data-roles such as header, content and footer ( as shown blow ) , as I mentioned above out sample consists of three views (home,sample and about) where “home” is the start (will not be AJAX loaded ) .
Sample “Page” (Razor view)
<div data-role="page" class="views sample index" id="sampleIndex">
<div data-role="header">
<h1>
    Header for sample
</h1>
</div>
<div data-role="content">
<h1>
    Hello sample!
</h1>
<div class="placeholder">
</div>
</div>
<div data-role="footer">
<h4>
    Footer for sample
</h4>
</div>
</div>
The sample view about has a data-role of page and I have given it the id of sampleIndex (View & Action) . This is the complete content of our view.
As the layout page (master ) is referring to a “site wide” scriptfile (/scripts/view/share/_Layout.js) we are able to fetch / insert scripts to the “DOM” as well,  the snippet below is a fragment of our thing.

$(function () {
   
$("div[data-role='page']").live("pagebeforecreate", function (event, ui) {    
       
var jsResource = $(this).attr("class").split(" ").join("/");
       
if (jsResource.length > 0)
           
$.getScript("/scripts/" + jsResource + ".js").fail(function () {
               
console.log(jsResource + " could not be loaded.")
           
}).done(function () {
               
console.log(jsResource + " loaded.")
           
});
   
});
});       
The script above is loaded once, and by using .live (jQuery) we are able to attach event handlers for elements that matches the current selector, now and in the future. in our case ;  The the pagebeforecreate occurs on a <div> having the data-role of page.
When this event occurs on “any” page, we use the class attribute the page being initialized (fetched & inserted ) to assemble a JavaScript url.
<div data-role="page" class="views sample index" id="sampleIndex">...
imageAs shown above the “class” attribute says “views sample index” ,giving us a url after some sting manipulation (i.e views/sample/index.js ), that reflects the Razor view or Page loaded (?) ( See image to right)
By using the jQuery getScript method its loaded and appended to the “DOM”






JQuery Mobile Events

When a page is shown or hidden in jQM two events are triggered.
pagebeforeshow is triggered on the page being shown before the transitions begins
pageshow is triggered on the page being displayed after its transitions are completed.
By attaching events handler to those we are able to execute upon the content od those pages both on show and hide, in your case we are appending data from AJAX calls (JSON/JSONP), WebSockets and render content by using Razor as well as render HTML Content by using jQuery tmpl.
So the contents if the scripts our looks like this.
$("#sampleIndex").live("pageshow", function () {
   
console.log("pageshow");
   
$(".placeholder").text("Hello Sample Page Placeholder");
});

$("#sampleIndex").live("pagehide", function () {
   
$(".placeholder").empty();
});
Some explanation of the JavaScript above (/Scripts/Views/Sample/index.js) read like this.
As we have the page data-role the name we are able to attach and event hander, in this case it sets the text of the placeholder class as well as it sends a text to the console?
Summary
This is a fragment of our solution, I hope I will start a discussion, and I know that there a other ways of doing this , the possibility to extend and override other events of jQuery Mobile may be another way.
Kind regards
Magnus Thor 

2 kommentarer:

  1. Thanks for sharing your info. I really appreciate your efforts and I will be waiting for your further write ups thanks once again.
    Google android app development| IPhone App Development|

    SvaraRadera
  2. Thanks for sharing your info. I really appreciate your efforts and I will be waiting for your further write ups thanks once again.
    Avatar Html5 Video Player

    SvaraRadera