Wednesday, 13 October 2010

SP2010 AJAX - Part 1: Boiling jQuery down to the essentials

This is the first article in a series which looks at building AJAX-style applications on SharePoint 2010. As you may have read in my last post, I recently gave a talk at the UK’s first SharePoint Saturday event on this topic, and this series goes into detail on what I covered there.

Series contents (note the ‘technique’ and ‘tip’ article types):

  1. Boiling jQuery down to the essentials (technique) - this article
  2. Using the JavaScript Client OM to work with lists (technique)
  3. Using jQuery AJAX with a HTTP handler (technique)
  4. Returning JSON from a HTTP handler (technique)
  5. Enable Intellisense for Client OM and jQuery (tip)
  6. Debugging jQuery/JavaScript (tip)
  7. Useful tools when building AJAX applications (tip)
  8. Migrating existing applications to jQuery/AJAX

If a developer is to have any hope of building AJAX-style applications, he/she needs to be able to change content on the page without a page refresh. After the initial learning curve, devs came to love .Net, but that oh-so-easy button_OnClick() event came at a price – a postback every time the page needs to be updated. For a time this was fine – both devs and end users effectively had low expectations on user experience for web applications. Now, however, things are different – postbacks are bad and SharePoint developers are arguably behind the curve (compared to ASP.Net devs) when it comes to building “modern-day” applications. Possibly the most popular tool for updating page content dynamically is jQuery. There’s no doubt about it, jQuery is a big topic. I don’t class myself as a guru, however my supposition is that jQuery can be boiled down to a handful of methods which give you a huge amount of power – this post covers these, and provides the foundation for building AJAX-style apps.

Core jQuery actions


Type

Code

Notes

Selector

$(‘#someId’)

Select an element by HTML ID e.g. <button ID=”someId” />

Selector

$(‘.someClass’)

Select an element by HTML/CSS class e.g. <button class=”someClass” />

Event

$(document).ready()
- jQuery also provides a shortcut for this: $()

Put code which should run on page load here

Event

.click()

Put code which should run when an element is clicked here (e.g. $(‘#myButton’).click())

Event

.change()

Put code which should run when an element is changed here (e.g. $(‘#myDropdown’).change())

Method

.html()

Sets the HTML of an element – extremely powerful as the element can be a single span or a huge main content div.

Method

.show()/.hide()

Shows or hides an element.

I genuinely think those tools give you most of what you need from jQuery, at least for page manipulation (but not AJAX – that comes later). Of course, you’re always going to need to do other things and once you understand how to use the basics, “the next tier” down of jQuery actions could be things like (N.B. no notes here, but you can guess what each statement does):

Type

Code

Selector

$(‘.someClass’)[0]
$(‘.someClass’).parent()
$(‘.someClass:visible’)

Event

$(document).ready()
.onmouseover()
.onkeyup()

Method

.fadeIn()/.fadeOut()
.append()
.wrap()
.addClass()

Going beyond these initial levels, I recommend jQuery In Action as the book to use to go deeper with jQuery.

Examples

To illustrate the ‘core’ jQuery tools, these are the examples I used in the “jQuery for page manipulation” section of my talk. For each example, I’ll give a quick overview, show the screenshots and show the HTML/jQuery code. Of course, flat screenshots don’t really convey what’s happening on the page, but just remember that there are no postbacks here.

  1. Showing/hiding elements

    Possibly *the* most fundamental thing we need to do when manipulating the page is to show and hide things (without a postback of course). In this example, clicking a button shows a spinner image – something which is often part of what happens when using jQuery with AJAX methods. Notice that, on page load (document.ready) jQuery is hiding the image immediately – an alternative would be to to add a style=”display:none” to the <img> element :

    jQuery_Demo1_Off
    <fieldset id="fldDemo1">
        <legend>Demo 1 - showing/hiding</legend>
        <div class="demoRow">
                <button id="btnDemo1" type="button">Show/hide image</button>
                <img src="../images/COB.SPSaturday.Demos/ajax-loader.gif" id="spinnerImg" />
        </div>
    </fieldset>
    <script type="text/javascript">
        $(function () {
            $('#spinnerImg').hide();
        });
     
        $('#btnDemo1').click(function () {
            if ($('#spinnerImg').is(':visible')) {
                $('#spinnerImg').hide();
            }
            else {
                $('#spinnerImg').show();
            }
        });
    </script>

  2. Setting the HTML of an element

    Setting the HTML content of an element on the page is equally important, and is as simple as getting a reference to the element and passing the HTML string to the .html() method. Although my example is trivial, the HTML contains images and elements with CSS applied to them – hopefully showing that the HTML could be anything between a small DIV on the page to a huge panel containing most of the page content:



    <fieldset id="fldDemo2"> 
        <legend>Demo 2 - setting HTML</legend> 
        <div class="demoRow"> 
            <button id="btnDemo2" type="button">Set HTML</button> 
            <span id="demo2Span"></span> 
        </div> 
    </fieldset> 
    <script type="text/javascript"> 
        $('#btnDemo2').click(function () { 
            $('#demo2Span').html('The <i>quick</i> <span id=\'brown\'>brown</span> <img src=\'/_layouts/images/COB.SPSaturday.Demos/fox.jpg\' /> jumped over the lazy <img src=\'/_layouts/images/COB.SPSaturday.Demos/dog.jpg\' />'); 
        }); 
    </script>

  3. Cascading dropdowns

    Although people sometimes make a big deal of cascading dropdowns (seems like there’s a new article on the topic every week), jQuery simplifies things considerably – the key is responding to the .change() event of the parent dropdown. Since we’re not covering AJAX yet, my example here uses dropdown items which are hardcoded in JavaScript rather than fetched from a query to the server. Note also that this code uses jQuery to populate the items in the parent dropdown even – the code would be simpler still if only the 2nd dropdown loaded items dynamically.


    <fieldset id="fldDemo2">
        <legend>Demo 3 - cascading dropdowns</legend>
        <div class="demoRow">
            <div><span class="demoLabel">Car manufacturer:</span><select id="carManufacturer"></select></div>
            <div><span class="demoLabel">Car model:</span><select id="carModel"></select></div>
        </div>
    </fieldset>
    <script type="text/javascript">
        $(function () {
            var output = [];
     
            var manufacturers = ['Select..', 'Ford', 'Vauxhall', 'Honda'];
            $.each(manufacturers, function (index, value) {
                output.push('<option value="' + value + '">' + value + '</option>');
            });
     
            $('select#carManufacturer').html(output.join(''));

        });
     
        $('select#carManufacturer').change(function () {
            var fordModels = ['Fiesta', 'Focus', 'Mondeo', 'Galaxy'];
            var vauxhallModels = ['Corsa', 'Astra', 'Insignia'];
            var hondaModels = ['Jazz', 'Pilot', 'Civic', 'Accord'];
     
            var selectedArray;
            if ($('select#carManufacturer').val() == 'Ford') {
                selectedArray = fordModels;
            }
            if ($('select#carManufacturer').val() == 'Vauxhall') {
                selectedArray = vauxhallModels;
            }
            if ($('select#carManufacturer').val() == 'Honda') {
                selectedArray = hondaModels;
            }
     
            var models = [];
            $.each(selectedArray, function (index, value) {
                models.push('<option value="' + value + '">' + value + '</option>');
            });
     
            $('select#carModel').html(models.join(''));
     
        });
    </script>
  4. Dimmed panel

    The .addClass() method is useful to change the style of elements without reloading the page. Of course, applying different CSS styles can cause dramatic changes to the page. To illustrate this I picked the idea of showing a dialog and ‘dimming’ the background – a UI technique very much in vogue and used, of course, by SharePoint 2010’s own dialog framework. If the CSS classes are already defined, a simple use of .addClass()/.removeClass() is the main thing that the code needs to do: 
     


    <!-- DIV for grey background, CSS makes larger than whole page -->
    <div id="dimmer"></div>  
    <!-- DIV for progress panel, CSS layers above page -->
    <div id="progressPanel">
        <a class="close" href="#" >
           <img id="close" src="/_layouts/images/COB.SPSaturday.Demos/close.jpg" />
        </a> 
        This is an important message!   
    </div>  
     
    <fieldset id="fldDemo4">
        <legend>Demo 4 - dimmed panel</legend>
        <div class="demoRow">
            <button id="btnDemo4" type="button">Dimmed panel</button>
       </div>
    </fieldset>
    <script type="text/javascript">
        $(function () {
            $('a.close').click(function () {
                $('div#progressPanel').fadeOut();
                $('div#dimmer').fadeOut().removeClass('dimmed');
            });
        });
     
        $('#btnDemo4').click(function () {
            $('div#progressPanel').fadeIn();
            $('div#dimmer').addClass('dimmed').fadeIn();
        });
    </script>
     
    Here’s the associated CSS:
    div#progressPanel
    {
        position:absolute; 
        width:200px; 
        height:150px; 
        z-index:20; 
        border:2px solid #222; 
        background: #FFF; 
        top: 50%; 
        left: 50%; 
        margin-top: -150px; 
        margin-left: -200px; 
        opacity: 1.0;
        -moz-opacity: 0.00;
        filter: alpha(opacity=0);
        display:none;
        padding:10px;   
        font-size:1.5em;
        font-weight:bold;
    }
     
    .dimmed
    {
        height: 100%;
        width: 100%;
        position:fixed;
        top: 0px;
        left: 0px;
        background-color: rgb(0, 0, 0);
        background-repeat:repeat;
        -moz-opacity: 0.70;
        opacity: 0.7;
        filter: alpha(opacity=70);
        z-index: 10;
    }
     
    .close 
    {
        top:0px; 
        float:right; 
    }
     
    .msgbox 
    {
        position:absolute; 
        width:300px; 
        height:200px; 
        z-index:200; 
        border:5px solid #222; 
        top: 50%; 
        left: 50%; 
        margin-top: -100px; 
        margin-left: -150px; 
    }   
     
    img#close 
    {
        border:none; 
        margin:5px;
    }

  5. Fetching HTML via AJAX

    Although this post attempts to focus purely on manipulating the page on the client side, here’s a quick example which does talk to the server (to whet your AJAX appetite). Here we are using one of jQuery’s AJAX methods to fetch the content of a page and put it within a DIV of the current page. This works fine for most pages but I ran into an issue with SharePoint admin pages which I didn’t get to the bottom of (see comment in code) – hopefully it proves how easy doing something like this is however, and consider that I could easily parse the result and do something more useful with it.


     

    <fieldset id="Fieldset1">
        <legend>Demo 5 - fetch HTML via AJAX</legend>
        <div class="demoRow">
            <button id="btnDemo5" type="button">Fetch HTML</button>
            <span id="demo5Span"></span>
       </div>
    </fieldset>
    <script type="text/javascript">
        // Some smoke and mirrors here unfortunately, SP pages 
        //  have some weird JavaScript redirect which would need to be solved 
        //  for this technique, so I'm using a (copied) flat HTML page..
        $('#btnDemo5').click(function () {
            $.get("/_layouts/COB.SPSaturday.Demos/settings_aspx.htm", function (data) {
                $('#demo5Span').html(data);
            });
        });
    </script>

These code samples (and those in the next articles) can be downloaded from http://db.tt/rUq5lm9

Next time - using the JavaScript Client OM + jQuery to work with lists.

Sunday, 3 October 2010

My SP2010, AJAX and jQuery code samples and slide deck

Had fun speaking at the first UK SharePoint Saturday event yesterday - around 400 attendees, great speakers/topics and great organisation. It felt like quite a lot had gone into my talk, so it was great that I had a full room with people standing round the edges and got great feedback (including on Twitter) afterwards. I’d written a lot of code samples on jQuery, the SharePoint Client OM (JavaScript version) and AJAX requests for the talk – over the next few articles I’ll publish these in some detail, but if you’re keen they can be downloaded along with my deck now from http://db.tt/rUq5lm9

I wanted to tackle this topic as I think it’s important that I (and probably you, if you’re a SharePoint developer) transition my skills to be able to build AJAX apps. Obviously different people are at different stages with this, but in my experience it’s certainly not the default approach yet. If you want some evidence on why it’s important, an interesting exercise is to compare the user experience when you re-order items on these two out-of-the-box SharePoint pages:

  • Manage User Properties (within the User Profile Service Application) - [CentralAdminHost]/_admin/ServiceApplications.aspx (terrible UI, I spent 4 hours reordering some properties on this page once!)
  • Manage Navigation (on a publishing site) – [PublishingSiteUrl]/_layouts/AreaNavigationSettings.aspx (much better UI, no postbacks)

A core theme of my talk was that whilst building AJAX-style apps on SharePoint 2010 seems complex, it can be distilled down to 3 core techniques. The full agenda of my talk was:

  • 3 core techniques for building AJAX-style apps on SharePoint 2010
    • Using jQuery to manipulate the page – although jQuery is a large topic, my view is that there are only about 7 key methods/events which give you most of what you need
    • Using the JavaScript Client OM to query lists/add list items – again, whilst the Client OM can do many things, once you understand the pattern for working with lists everything else is similar
    • Using jQuery’s 3 AJAX methods with a HTTP handler – for me this approach is simpler than WCF, and is a key technique which unlocks the door to AJAX apps since you can write whatever server-side code you require and call it asynchronously
  • Tips and tricks
    • How to get Intellisense with jQuery and the Client OM
    • How to debug JavaScript
    • Using FireFinder to hone your jQuery selectors
    • How to easily return JSON-formatted data from a handler and work with it on the client
  • Migrating an existing SharePoint app from postbacks to jQuery/AJAX
    • Here I demo’d the steps I used to migrate the application page in my SP2010 Feature Upgrade Kit to jQuery/AJAX (courtesy of code snippets)

Since you never fully grok new learnings from a 1 hour presentation, a couple of attendees asked if I’d expand on the contents in my blog, and that’s exactly what I want to do. So my next blog series will cover this ground in close detail. As I mentioned in my talk, I don’t consider myself a guru in this area so comments/suggestions especially welcome!

That link again to my code samples/deck is http://db.tt/rUq5lm9