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

Tuesday, 28 September 2010

Set object caching user accounts with PowerShell

In all installations of SharePoint, it’s important to properly configure object caching so that SharePoint can efficiently retrieve cached versions of items where possible. In my experience, this is one of THE most frequently forgotten configuration steps – yet Technet is clear that SharePoint cannot perform optimally without this being done. Object caching configuration mainly involves the configuration of two specific user accounts which SharePoint will use to simulate a reader and high-privileged user. If these accounts are not configured, you’ll see entries like this in the Windows event log:

Object Cache: The super user account utilized by the cache is not configured. This can increase the number of cache misses, which causes the page requests to consume unneccesary system resources.

The full details of why this configuration is necessary are in the Technet article Configuring object cache user accounts. The article outlines the process for performing the configuration, but bizarrely (IMHO) lists a process which is half PowerShell, half manual steps in Central Admin. My guess is that, just like software, shipping documentation has compromises too, and this article didn’t yet make the cut to receive the full treatment. I’ve written some PowerShell which does the full configuration – make sure you edit it to use your account names and web application URLs. You'll need to paste this into a tool which can strip out HTML, before saving as a .ps1 file. If anyone has any trouble working with it, let me know and I'll post the actual file somewhere.

Add-PSSnapin "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue
 
# EDIT THIS TO ENSURE ACCOUNTS ARE CORRECT FOR ENVIRONMENT..
 
$objectCachePortalSuperReader = "sp2010\portalsuperreader" 
$objectCachePortalSuperUser = "sp2010\portalsuperuser" 
 
$allWebApps = ("http://one.myCompany.com", "http://two.myCompany.com") 
 
Function ConfigureObjectCachingOnWebApp([Microsoft.SharePoint.Administration.SPWebApplication]$webApplication)
{
      Write-Host ("Processing " + $webApplication.Url);
 
      try
      {
            GrantPolicy $webApplication $objectCachePortalSuperReader FullRead
            GrantPolicy $webApplication $objectCachePortalSuperUser FullControl
 
            SetPropertyOnWebApp $webApplication "portalsuperuseraccount" $objectCachePortalSuperUser
            SetPropertyOnWebApp $webApplication "portalsuperreaderaccount" $objectCachePortalSuperReader
 
            $webApplication.Update()
 
            Write-Host -BackgroundColor DarkGreen -ForegroundColor White ("Configured " + $webApplication.Url);
      }
      catch
      {
            Write-Host -BackgroundColor DarkRed -ForegroundColor White ("Failed to configure " + $webApplication.Url + ". Error details : " + $_)        
      }
}
 
Function GrantPolicy([Microsoft.SharePoint.Administration.SPWebApplication]$webApplicationForPolicy, [string]$userOrGroup, 
      [Microsoft.SharePoint.Administration.SPPolicyRoleType]$policyLevel)
{
      $policy = $webApplicationForPolicy.Policies.Add($userOrGroup, $userOrGroup) 
      $policy.PolicyRoleBindings.Add($webApplicationForPolicy.PolicyRoles.GetSpecialRole($policyLevel)) 
}
 
Function SetPropertyOnWebApp([Microsoft.SharePoint.Administration.SPWebApplication]$webApplicationForProperty, [string]$property, 
      [string]$propertyValue)
{
      $webApplicationForProperty.Properties[$property] = $propertyValue 
}
 
# inline script starts here..
 
$confirmed = Read-Host "This script must be edited before running for correct user accounts for each environment - have you done this? Enter Y to continue or N to exit."
if ($confirmed -eq 'y')
{
      foreach($webAppName in $allWebApps)
      {
            $webApp = Get-SPWebApplication -Identity $webAppName -ErrorAction SilentlyContinue
 
            if($webApp)
            {
                  ConfigureObjectCachingOnWebApp($webApp)     

            }
            else
            {
                  Write-Host -ForegroundColor DarkRed ("Failed to find web app '" + $webAppName + "' in this environment. ")
            }
      }
}
 
Write-Host -BackgroundColor Blue -ForegroundColor White "Script completed"

Monday, 13 September 2010

Speaking on SP2010, jQuery and AJAX at the 1st UK SharePoint Saturday

In a couple of weeks I’ll be speaking at the first ever UK edition of the popular SharePoint Saturday event. It should be a great day with lots of SharePoint folks from around the country and beyond – the speaker list looks great and we even have Joel Oleson (ex-MS IT) and Mark Miller (www.EndUserSharePoint.com) flying in from the States. Since the original allocation “sold-out” (in loose terms, the event is free!), capacity has just been extended to 400, so at the time of writing you still have chance to register.

My topic this time is about a transition that I’ve been trying to address for myself recently, and suspect quite a lot of SharePoint developers are thinking about - here’s the blurb:

SharePoint, jQuery and AJAX - a beginner's survival guide

It takes a different approach to build SharePoint apps with a slick AJAX experience - getting rid of those nasty postbacks involves declining some help from .Net and learning new techniques. Whilst the answers often lie with the Client Object Model and jQuery, both are hefty topics so the barrier can be intimidating. This talk aims to boil things down to "3 core techniques to survive by", with step-by-step demos to show the development process. Tips and tricks such as enabling jQuery intellisense, debugging JavaScript and using JSON will be covered. To pull the concepts together, the session will round off with a demo migration of an existing mini-application from postbacks to AJAX. Building experiences that users love is simpler than you think!

I’ll publish the slides here after the talk, but as ever much of the goodness will be in the demos – right now I’m not sure if the event has the facility to record the talks unfortunately. If you’re within reach and are thinking of coming, no doubt the whole day will have great content.

Hope to see you there!