Thursday, February 24, 2011

Dynamically Appending Elements to jQuery Mobile ListView

I've been developing with jQuery Mobile the past several weeks and the application I'm working on has a listing page where I am retrieving the results via $.ajax and then dynamically appending the results to the current page. I started out with a page very much like the following...
<div data-role="page" id="hackerNews">
    
  <div data-role="header" data-backbtn="false">
    <a id="btnRefresh" href="#" data-icon="refresh">Refresh</a>
    <h1>Hacker News  
      <span id="itemCount" class="count ui-btn-up-c ui-btn-corner-all">0</span>
    </h1>
  </div>
    

  <div id="content" data-role="content">
    <ol class="newsList" data-role="listview"></ol>
  </div>
        
</div>

<script id="newsItem" type="text/x-jquery-tmpl">
  <li data-messageId="${id}" class="newsItem">
    <h3><a href="${url}">${title}</a></h3>
    <p class="subItem"><strong>${postedAgo} by ${postedBy} </strong></p>
    <div class="ui-li-aside">
      <p><strong>${points} points</strong></p>
      <p>${commentCount} comments</p>
    </div>
  </li>
</script>
...but when I tried to dynamically render the ListView into the content area the browser ended up rendering something like the screenshot below on the left, where I had expected it to render something like the screenshot on the right.

In the following example, I will pull the most recent items from Hacker News and display them inside of a jQuery Mobile ListView.

After some digging and researching, it turns out the difference between the left screenshot and the right is just one line of code. All you have to do is to call the $.listview() widget off of your list jQuery object... so, something like $( "#myUnorderedList" ).listview();.

Make sure to notice line #61, which is the main difference between the screenshot above!
var hackerNews = (function( $, undefined ) {
  var pub = {};

  pub.init = function() {
    //Refresh news when btnRefresh is clicked
    $( "#btnRefresh" ).live( "click", 
      function() {
        pub.getAndDisplayNews();
      });
        
    //When news updated, display items in list
    amplify.subscribe( "news.updated", 
      function( news ) {
        displayNews( news );
      });

    //When news updated, then set item count
    amplify.subscribe( "news.updated", 
      function( news ) {
        $("#itemCount").text( news.items.length );
      });    
  };
    
  pub.getAndDisplayNews = function() {
    //Starting loading animation
    $.mobile.pageLoading();    

    //Get news and add success callback using then
    getNews().then( function() {
      //Stop loading animation on success
      $.mobile.pageLoading( true );    
    });    
  };
    
  function getNews() {
    //Get news via ajax and return jqXhr
    return $.ajax({
      url: "http://api.ihackernews.com/" + 
         "page?format=jsonp",
      dataType: "jsonp"
    }).then( function( data, textStatus, jqXHR ) {
      //Publish that news has been updated & allow
      //the 2 subscribers to update the UI content
      amplify.publish( "news.updated", data );
    });
  }
    
  function displayNews( news ) {
    var newsList = $( "#hackerNews" )
      .find( ".newsList" );
        
    //Empty current list
    newsList.empty();
        
    //Use template to create items & add to list
    $( "#newsItem" ).tmpl( news.items )
      .appendTo( newsList );
        
    //Call listview jQuery UI Widget after adding 
    //items to the list for correct rendering
    newsList.listview( "refresh" );    
  }
    
  return pub;
}( jQuery ));

hackerNews.init();
hackerNews.getAndDisplayNews();
I am utilizing some of the new jQuery 1.5 Deferred syntax and also the publish/subscribe methods from the Amplify Library released by appendTo recently. I'm also using the Revealing Module Pattern to protect the global scope.



View Demo Edit Demo

Tuesday, February 22, 2011

jQuery.Deferred to Tell When Certain iframes Are Loaded

Since jQuery 1.5 came out I've been intrigued about the new jQuery.Deferred feature, but hadn't used it until now. You might think that Deferreds are isolated to only jQuery.ajax requests, but they are much more flexible than that. jQuery.ajax utilize defferds, but you can also use them to define your own set of promises.
Eric Hynds wrote an awesome blog post entitled Using Deferreds in jQuery 1.5 describing the inns and outs of jQuery Deferreds in much more detail, but I thought I'd share a use case that I found helpful in a recent project.
I'm working on a project where there are multiple hidden iframes loaded on the page (don't ask why LOL) and I needed a way to tell if they were all loaded. Almost immediately I thought about using the new Deferred feature!

(function($) {

function iFrameLoaded( id, src ) {
   var deferred = $.Deferred(),
      iframe = $( "" ).attr({
         "id": id,
         "src": src
      });

   iframe.load( deferred.resolve );
   iframe.appendTo( "body" );

   deferred.done(function() {
      console.log( "iframe loaded: " + id );
   });

   return deferred.promise();
}

$.when(
   iFrameLoaded("jQuery", "http://jquery.com"),
   iFrameLoaded("appendTo", "http://appendto.com"))
.then( function() {
   console.log( "Both iframes loaded" );
});
    
}(jQuery));

The above code creates a new jQuery.Deferred object (line 4) and iframe element. Once the iframe is loaded, we tell the deferred object to resolve itself (line 10). At that point we define our own event handler to respond to when the deferred is done (line 13). In this case we just print to the console that "iframe loaded". Then we return the deferred promise (line 17) so that we can use it in the new jQuery.when method.

Next we call the jQuery.when method (line 20) and pass all the promises we want fulfilled before we proceed. Once all the iframes are loaded, then the then method will execute (line 23) printing out "Both iframes loaded" to the console.



View Demo Edit Demo

Note: This same concept can also be applied to a set of images loading and many other applications.

Thursday, February 17, 2011

ASPInsiders Twitter List


The ASPInsiders is a select group of international professionals in ASP.NET technologies (Web Forms, MVC, Web Pages, etc...)

Jason Gaylord has assembled a list of ASPInsiders into a new ASPInsiders Twitter List that you can follow to keep track of the latest in ASP.NET technologies.

"The ASPInsiders team spends countless hours answering questions and giving guidance to other ASP.NET developers, as well as providing feedback and diretion on new features for future ASP.NET releases. Their work and contributions are invaluable." 
Product Unit Manger, Web Platforms, Microsoft Corporation



ASPInsiders Twitter List

Note: The ASPInsiders group is different from the Microsoft MVP award. Many of the ASPInsiders either are or have been a Microsoft MVP as well, but there are also many that have not. There is not a 1:1 correlations between the two groups.  

Wednesday, February 16, 2011

Free Julian on JavaScript Series

If you are new to JavaScript or just don't know it as well as you should, then I encourage you to watch the Julian on JavaScript Series on DevExpress.

Julian M Bucknall wrote an awesome series a while back called JavaScript for C# Developers that I remember going through that helped me become a better JavaScript developer.

Julian has planned out 4 sessions thus far, and has completed one of them already. If you can't make the live webinar, then the sessions will be available to view online afterwards.



Julian on JavaScript I (07-Feb-2011)

Writing JavaScript when you already know C# can seem like a piece of cake: after all it's a C-like language, so what can go wrong? Julian starts off a series of webinars to teach you the basics of writing JavaScript. No experience is necessary apart from an understanding of C#. This webinar will concentrate on types.

Watch Online



Julian on JavaScript II (28-Feb-2011)

Writing JavaScript when you already know C# can seem like a piece of cake: after all it's a C-like language, so what can go wrong? Julian continues a series of webinars that teach you the basics of writing JavaScript. This webinar will concentrate on objects and assumes you've watched part I.

Register Online



Julian on JavaScript III (07-Mar-2011)

Writing JavaScript when you already know C# can seem like a piece of cake: after all it's a C-like language, so what can go wrong? Julian continues a series of webinars that teach you the basics of writing JavaScript. This webinar will concentrate on functions and assumes you've watched parts I and II.

Register Online



Julian on JavaScript IV (28-Mar-2011)

Writing JavaScript when you already know C# can seem like a piece of cake: after all it's a C-like language, so what can go wrong? Julian continues a series of webinars that teach you the basics of writing JavaScript. This webinar will dive deep into writing good JavaScript and assumes you've watched the previous three parts.

Register Online

Tuesday, February 15, 2011

Mocking jQuery Ajax Calls with Random Templated Data

In a recent blog post, Mocking the jQuery Ajax Call in ASP.NET MVC 3 Music Store , I showed you how you could use the $.mockjax library, written by Jonathan Sharp, to intercept AJAX requests and return a mocked response. This tool can be especially useful when trying to code your front-end, while the back-end piece is either isn't available or accessible.

Another useful library that you may consider when building quick prototypes is $.mockJSON, written by Menno van Slooten. This library has some of the same features as $.mockjax, but the piece I'd like to focus on is the random data tempting feature. This can be very handy when you want to mock a JSON response from a AJAX call, but instead of manually building the response you can build a template to do it for you.

To demonstrate using this random data technique, I decided to use the SlickGrid jQuery Plugin and populate it with the JSON response from an AJAX call. Since the AJAX call doesn't exist, I am going to use $.mockjax to return the response using random data generated from $.mockJSON.

The following code is what is necessary to populate the SlickGrid with data from an AJAX call.

(function($) {

var grid,
  columns = [
    {id:"firstName", name:"First Name", field:"firstName", width:70},
    {id:"lastName", name:"Last Name", field:"lastName", width:70},
    {id:"email", name:"Email", field:"email", width:170},
    {id:"percentHealth", name:"% Health", field:"percentHealth", width:90, formatter:GraphicalPercentCompleteCellFormatter},
    {id:"birthday", name:"Birthday", field:"birthday", width:70},
    {id:"married", name:"Married", field:"married", width:50, formatter:BoolCellFormatter}
],
  options = {
    editable: false,
    enableAddRow: false,
    enableCellNavigation: true,
    rowCssClasses: function(item) {
      return (item.percentHealth >= 80) ? 
        "healthy" : "";
    }
  };
        
$.ajax({
  url: "/Contact/List",
  type: "GET",
  dataType: "json",
  success: function(data, textStatus, xhr) {
    grid = new Slick.Grid("#myGrid", 
      data.contacts, columns, options);
  },
  error: function(xhr, textStatus, errorThrown) {
    console.log("Error: " + textStatus);
  }
});

function BoolCellFormatter(row, cell, value, 
  columnDef, dataContext) {
  return value ? "✔" : "";
};
    
}(jQuery));
At this point, I don't have the '/Contact/List' endpoint defined so if I executed the above code I would get a GET http://fiddle.jshell.net/Contact/List 404 (NOT FOUND) error in my console. If I did want to test the behavior of my front-end without depending on a back-end existing, then I can add an additional $.mockjax statement to intercept the call and respond with some random data provided by $.mockjson.

$.mockjax({
    url: '/Contact/List',
    responseTime: 750,
    responseText: $.mockJSON.generateFromTemplate({
        "contacts|50-500": [{
            "married|0-1": true,
            "email" : "@EMAIL",
            "firstName": "@MALE_FIRST_NAME",
            "lastName": "@LAST_NAME",
            "birthday": "@DATE_MM/@DATE_DD/@DATE_YYYY",
            "percentHealth|0-100": 0 
        }]
    })
});
The above code will intercept any AJAX requests with the '/Contact/List' endpoint and will use the template passed to $.mockJSON as the response. The template will generate between 50 and 500 contacts each having male first names and having a health ranging from 0 to 100. Each contact will have a random email, birthday, and married boolean field. You can find out more information as to what $.mockJSON supports and how you can extend it from their website.

The following JSON snippet is an example of what the above $.mockJSON template will generate. The above template would generate between 50 to 500 contacts, but for brevity I just included 4.

{
  "contacts": [{
    "married": false,
    "email": "u.lewis@gonzalez.com",
    "firstName": "Paul",
    "lastName": "Martinez",
    "birthday": "12/16/2005",
    "percentHealth": 37},
  {
    "married": false,
    "email": "k.hernandez@smith.com",
    "firstName": "Daniel",
    "lastName": "Gonzalez",
    "birthday": "07/11/1997",
    "percentHealth": 1},
  {
    "married": true,
    "email": "c.thomas@taylor.com",
    "firstName": "David",
    "lastName": "Lewis",
    "birthday": "04/13/2007",
    "percentHealth": 62},
  {
    "married": true,
    "email": "v.davis@lee.com",
    "firstName": "Richard",
    "lastName": "Rodriguez",
    "birthday": "05/10/2007",
    "percentHealth": 6}]

  //A bunch more...

}
Now, since we have some data coming back from our AJAX request, we can run our code again and proceed to get our front-end working as intended.



View Demo Edit Demo

Thursday, February 10, 2011

Mocking the jQuery Ajax Call in ASP.NET MVC 3 Music Store

Sometimes the front-end and back-end of your application progress at different speeds. In order for each layer to progress independently it is optimal if the front-end piece can mock the results of the back-end.

I have grabbed the AJAX section from the recently updated ASP.NET MVC 3 Music Store and I slightly tweaked it below.

$(".RemoveLink").click(function() {
  var recordToDelete = $(this).attr("data-id");

  if (recordToDelete) {
    $.post("/ShoppingCart/RemoveFromCart", {
      "id": recordToDelete
    }, function(data) {
      if (data.ItemCount === 0) {
        $('#row-' + data.DeleteId).fadeOut('slow');
      } else {
        $('#item-count-' + data.DeleteId)
          .text(data.ItemCount);
      }

      $('#cart-total').text(data.CartTotal);
      $('#update-message').text(data.Message);
      $('#cart-status')
        .text('Cart (' + data.CartCount + ')');
    });
  }
});    

Let's say for example, that the controller action wasn't yet implemented, but the front-end developer still wanted to progress in their code. To do this we are going to introduce a new tool called Mockjax to simulate a response from a jQuery ajax call.

The following code mocks any call to the /ShoopingCart/RemoveFromCart URL and will respond with the following object literal.

$.mockjax({
  url: "/ShoppingCart/RemoveFromCart",
  responseTime: 750,
  responseText: {         
    ItemCount: 5,
    DeleteId: 1,
    CartTotal: 112.45,
    Message: "Your cart has been updated!",
    CartCount: 16
  }
});

The great thing about the above technique is that you are guaranteed the same response will be returned no matter what request you made to the ajax call. For example, this approach can be very good for Unit Testing. However, if you are trying to demonstrate the code to a client or just want to play around with the behavior then you might want something a little more flexible and dynamic.

Fortunately, Mockjax not only allows you to return a static set of responseText or repsonseXML, but it also lets you dynamically decide what content you want returned, which is what we are going to demonstrate below.
Note: Mockjax offers much more control than what I am showing in this example. I encourage you to check out all of it's features.
$.mockjax({
  url: "/ShoppingCart/RemoveFromCart",
  responseTime: 750,
  response: function(settings) {
    var row = $("#row-" + settings.data.id),
      itemCount = +row.find("td").eq(2)
        .text(function(index, text) {
          return +$.trim(text) - 1;
        }).text(),
      cartTotal = 0, cartCount = 0;
        
    $("table tr").each(function(index, element) {
      var row = $(element),
        price = +row.find("td").eq(1).text(),
        quantity = +row.find("td").eq(2).text();

      if (price && quantity) {
        cartCount += quantity;
        cartTotal += price * quantity;
      }
    });

    this.responseText = {         
      ItemCount: itemCount,
      DeleteId: settings.data.id,
      CartTotal: cartTotal.toFixed(2),
      Message: "Your cart has been updated!",
      CartCount: cartCount
    };
  }
});

This might seem like excessive front-end code, but the intent is to simulate what the back-end might return in order for the front-end to respond in an appropriate manner. The code is doing some basic calculations to determine what the Shopping Cart quantity and values might be after deleting an item.
Note: The mockjax response code above could have been simplified somewhat if I had modified the MVC 3 View rendering the HTML, but as in many projects you don't always have access to change the existing output. I decided to go with that approach instead of changing the MVC 3 View code in this blog post.

Once the back-end code is complete, then you can remove the $.mockjax call from your code-base and it will be hitting your back-end resource instead of the mocked response.

I captured the HTML, CSS, and JavaScript from the MVC 3 Music Store and put it in the following jsFiddle for you to execute and play around with. The main piece that I added was the mockjax code to simulate the AJAX request and response from the server.


Note: You might also consider mockjax to be a great Unit Testing tool as you are developing your front-end code and the back-end isn't yet implemented.


Wednesday, February 09, 2011

Feature Detect Placeholder to Adjust jQuery Mobile Layout

If you take a look at most of the jQuery Mobile Documentation you will see heavy use of labels and input elements inside of a fieldcontain data-role. The great thing about this technique is that it looks good on portrait layouts (labels on top & input on bottom) and also adjusts for landscape layouts (labels on the left & input on the right).



The HTML to generate the above screenshots can be found in the following markup.

 
<div data-role="page" id="login">
    
  <div data-role="header">
    <h1>Acme Corporation</h1>
  </div>
    
  <div data-role="content">
    <form id="frmLogin" class="validate">
      <div data-role="fieldcontain">
        <label for="email">Email: </label>
        <input type="text" id="email" 
          name="email" class="required email" />
      </div>
            
      <div data-role="fieldcontain">
        <label for="password">Password: </label>
        <input type="password" id="password" 
          name="password" class="required" />
      </div>
            
      <div class="ui-body ui-body-b">
        <fieldset class="ui-grid-a">
          <div class="ui-block-a">
            <button id="btnCancel" data-theme="d" 
              data-icon="delete">Cancel</button>
          </div>
          <div class="ui-block-b">
            <button id="btnLogin" type="submit" 
              data-theme="a" data-icon="check">
                Log In
            </button>       
          </div>
        </fieldset>
      </div>
    </form>
        
  </div>
    
</div>

I recently did a mock-up for a client using this technique, but they wanted to use the HTML5 form placeholder technique instead. I told the client that this was possible, but mentioned that not all browsers support this technique.

So, I decided to use a Progressive Enhancement approach to this problem using the Modernizer JavaScript library. I wrote some JavaScript to detect if the browser supports the placeholder HTML5 attribute and if it does, then I hide and take the text from the label element and then push the value into the input element's placeholder attribute.

 
// if placeholder is supported
if ( Modernizr.input.placeholder ) {

  $( "input" ).each( function(index, element) {

    var placeholder = 
      $("label[for=" + element.id + "]")
        .hide().text();

    $(element)
      .addClass("ui-input-text-placeholder")
      .attr("placeholder", placeholder);

  });

}

You can view a running example of the above code from this jsFiddle. If you are running Google Chrome, then you'll notice the label's are embedded as placeholder's within the input elements, but if you are using Firefox or Internet Explorer 6/7/8 then you'll notice the default label and input technique that is default in most of the jQuery Mobile documentation.



I've added some screenshots of the placeholder technique in case you are reading this blog entry in a browser that doesn't support the HTML5 form placeholder attribute.



Monday, February 07, 2011

jQuery Mobile Form Validation

Note: I've updated the following post to work with jQuery Mobile 1.0+. After the beta version they deprecated the Orientation Classes that this post originally used to handle the layout of the error messages. jQuery Mobile recommends using CSS3 Media Queries instead. If you need support for older browsers then respond.js is a nice polyfill for this.

I am working on a jQuery Mobile application and one of the standard requirements when you have form elements is to provide client-side validation.

I hadn't seen an example of that yet, so my first inclination was to use the jQuery Validation plugin. As it turns out, the implementation is about the same as you would expect with a non-mobile solution.


In this case I just adding metadata validation classes to the input elements to indicate what rules (example: required, email, etc...) need to be checked when the form is submitted. You can provide these rules also programmatically, but I won't focus on that technique in this post. You can find more details about how to provide validation rules at runtime in the plugin's documentation.

In JavaScript, all you have to do is to call the validate() method off of the form element and provide a submitHandler that will perform the action once your form has passed all it's validation rules.


An interesting challenge comes on mobile devices when considering how to display the validation message in portrait versus landscape mode. I wanted the alignment of the errors to show up different depending upon the orientation.

As it turns out, the solution to this problem was a simple matter of changing my CSS. We can use CSS3 Media Queries to style the page depending on the orientation of the mobile device. By using the following CSS the validation errors will display differently depending if the mobile device is in portrait or landscape mode.


The following is an embedded working jsFiddle example using all the above HTML, CSS, JavaScript, and Resources. If you want to play and tweak with the code snippets you can click the "+" to the right of the "Resources" tab.



Since simulating portrait vs landscape mode on a desktop browser is slightly difficult I took some screenshots from my iPhone for you to see the difference.


Friday, February 04, 2011

jQuery Conference Boston 2010 Video: Intro to jQuery UI


The presentations from last year's jQuery Conference Boston 2010 are now online for you to view. You can click the above picture to watch my introduction to jQuery UI. The material is targeted to someone who hasn't seen jQuery UI at all or knows very little about it.

Slides

I have hosted my slides from the presentation if you are interested.

Other Presentations

In addition you can check out most of the other sessions from the jQuery Conference Videos page.

Some of talks the talks that I found particularly interesting were...


Wednesday, February 02, 2011

Video: Good C# Habits Can Encourage Bad JavaScript Habits

Today I recorded a Webinar with DevExpress entitled "Good C# Habits Can Encourage Bad JavaScript Habits". The webinar is embedded below.

The talk was spurred by a recent Fornt-end Architecture Review I performed where the background of the developers was primarily C#. The project was almost entirely written in JavaScript and I noticed a common set of bad JavaScript practices that appeared to have their influence in good C# techniques.

These thoughts turned into a series of articles that I posted several months ago on Enterprise jQuery and I have recently pooled the articles into the following presentation.

I hope that this presentation will help you prevent some of these mistakes in your projects and to let you know, I've made all these mistakes myself :)



Resources


At the end of the presentation I list several resources that you might want to dig into and research for yourself.

Slides and Articles
  • I have hosted the slides from the video. I utilized an HTML5 Presentation tool and the slides are best viewed using either Google Chrome or Firefox. 
  • The article series this video was based on can be found on Enterprise jQuery
Tools
Books
Articles
Video

Mix 11 Conference

If you like this topic, then please consider voting for it to be included in the Microsoft Mix 11 conference by clicking the following tweet. Voting ends on Feb 4th. Thanks!