Monday 31 October 2011

Specifying Sort Order When Querying the SharePoint List Web Service with CAML and jQuery (via Lists.asmx)

I had a couple of problems today with specifying the sort order of data returned from a CAML query via a jQuery AJAX call. It seemed that no matter what setting I put in, it always seemed to return an unordered resultset.

I resolved the problem by looking at the requests in Fiddler that were produced by U2U CAML query Builder. The main problem was that I wasn't correctly wrapping the CAML "Query" node in a parent "query" node. Now you only have to do this when you're doing jQuery calls directly against web services - and are shielded from this somewhat when you are calling the SharePoint client object model (for details you can look here http://msdn.microsoft.com/en-us/library/gg701783.aspx). Why I'm using web service calls directly is a discussion for another time (and I wouldn't automatically turn to using it as a preference - as described here http://msdn.microsoft.com/en-us/library/ee539764.aspx) - but I'll say for now that it is for consistency with existing code (The client object model is using the web services underneath as well, but has batching facilities). See below for an example of a jQuery call which does sorting that worked for me. U2U CAML Query builder will also give you the valid internal name for the field.

var errorMessage;
  //Add order by if variable is set in other part of page (so it can be switched on or off on a page-by-page basis.
  if (typeof missingCategoryDisplayMode_IsOnline != 'undefined' && missingCategoryDisplayMode_IsOnline == true  ) //Variable should be set by another content query web part on page
  {
   var orderBy = "\
       \
      ";
  }

try
  {
   var contentCategoryCAML = "<?xml version='1.0' encoding='utf-8'?> \
        <soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' \
           xmlns:xsd='http://www.w3.org/2001/XMLSchema' \
           xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'><soap:Body> \
           <GetListItems xmlns='http://schemas.microsoft.com/sharepoint/soap/'> \
           <listName>Content Categories</listName> \
           <query>\
           <Query xmlns=''>\
           " + orderBy +
           "</Query>\
           </query>\
           <viewFields>\
           <ViewFields xmlns='' />\
           </viewFields>\
           <queryOptions>\
           <QueryOptions xmlns=''/> \
           </queryOptions></GetListItems> \
         </soap:Body></soap:Envelope>";
   $.ajax({
    url: listUrl,
    type: "POST",
    dataType: "xml",
    data: contentCategoryCAML,
    complete: ContentCategoryResult,
    contentType: "text/xml; charset=\"utf-8\""
   });
  }
  catch (ex)
  {
   displayError("There was an error retrieving data from the Content Categories list. Please see IT support for assistance.");
   return;
  }
  
  function ContentCategoryResult(xData, status)
  {
   $(xData.responseXML).find("z\\:row").each(function () 
   {           
      var Title = $(this).attr("ows_LinkTitle");           
      arrContentCat.push(Title);  //Adding the results in an array
   });
  }


This adds items to an array that are used later for rendering. I needed a different sort order based on the page - so this was done using a seperate javascript file that is placed into a Content Editor Web Part on pages to set the sort order variable.

I also use the SharePoint client model to programatically determine the site collection path and to ensure that the list web service of the current site collection root is used (you can't determine that just by the url):

function MenuInitialize()
 {
     var clientContext = new SP.ClientContext();
        var siteColl = clientContext.get_site();
        myweb = siteColl.get_rootWeb();
        clientContext.load(myweb);
        /* Execute async required*/
        clientContext.executeQueryAsync(Function.createDelegate(this, executeRequestAndRender), Function.createDelegate(this, getFailed));
 }
 
 function executeRequestAndRender() {
  var siteCollectionUrl = myweb.get_serverRelativeUrl();
  var listWebServiceUrl = siteCollectionUrl + "/_vti_bin/lists.asmx"
  //When at the root, siteCollectionUrl is '/', but other sites have /sitecollection/sites
  listWebServiceUrl = listWebServiceUrl.replace('//', '/');
  /* When complete, we can render requests */
  RenderMenu_ContentCategoryList(listWebServiceUrl);
 }


For the SharePoint Client Object model to work of course, you should always tell Script on demand (SOD) to process the code that references the SP client object model only when the SP.js file has been loaded:

$(document).ready(function()
{
 /*Ensure that the Sp.js is loaded (using Script on Demand (SOD) SharePoint library) so the client object model functions correctly */
 SP.SOD.executeOrDelayUntilScriptLoaded(MenuInitialize, 'SP.js');

DDK

Tuesday 18 October 2011

SharePoint 2010 - My jQuery Scripts are Broken on the Publishing Portal Thumbnails.aspx Page. All other pages are fine.

I've had this problem many times in ASP.NET but never in SharePoint 2010. Today, one of our jQuery script implementations was failing on just a couple of the SharePoint pages - in particular the Publishing Portal Thumbnails Page.

All the jQuery objects were returning null values even though it worked for all the pages in the SharePoint site. The problem is back to that golden oldie of the jQuery object shortcut of $ conflicting with the Microsoft AJAX framework. Both frameworks use the $ as an object shortcut and so this causes problems. I almost felt nostalgic getting this exception :o).

Why does it only happen on a couple of pages in SharePoint 2010? They are the only ones which have script references to the MS AJAX javascript libraries.

There are ways around this using aliases (via the jQuery.noConflict() command) - but the simplest way is to just use jQuery as a best practice when working within SharePoint 2010 -  with a find and replace of "$(" with "jQuery(" as needed. This fixed the problem.

Too easy!

DDK

Wednesday 12 October 2011

CSS Positioning Refresher - Relative vs Absolute vs Static vs Fixed - SharePoint 2010 Branding

My current client is a media company who wanted branding done as part of a SharePoint 2010 Portal implementation project. One problem arose because their standard operating environment uses Internet Explorer 7. Our IE 7 specific issues arose because of IE7's position behaviour and it's interaction with a dynamic pop-down DIV that we were injecting with jQuery.

In IE7 (not in IE8+ or Firefox), our whole content div in SharePoint was getting pushed down by our hidden div used as part of the pop-down menu. Turns out our resolution to fix this IE 7 was to make our hidden div to use position:absolute rather than relative/static.

The critical difference between relative and absolute in particular is not how it changes the behaviour of the div - but rather how it affects the flow of OTHER elements on the page. This is particularly important when you are injecting elements into SharePoint with jQuery. The best explanation of CSS positioning (and how it affects other html elements) I've found is here:

http://www.w3schools.com/css/css_positioning.asp


RELATIVE: The content of relatively positioned elements can be moved and overlap other elements, but the reserved space for the element is still preserved in the normal flow.
ABSOLUTE:
Absolutely positioned elements are removed from the normal flow. The document and other elements behave like the absolutely positioned element does not exist (Yes! this is what we really want)

This still doesn't explain the rendering difference in IE7 vs IE8 vs Firefox apart from the fact that other browsers seem to be more forgiving when specifying your CSS positioning compared to IE7 (in Standards mode).

DDK

Wednesday 5 October 2011

SharePont 2010 - Why is Inline Editing not working even when enabled for the current view?

One of my colleagues at Oakton had issues in that a SharePoint 2010 Custom List wasn't allowing editing inline.

Even when modifying the view and enabling the "Allow Inline" editing property of the list view - no errors, it just didn't work and the Edit icon just opened the full blown SharePoint modal dialog box as usual.



The problem was that the list view must use the Default Style for Inline editing to work.



DDK