SPServices Stories #9: Developing with Client-side Technologies: jQuery, REST, SPServices and jsRender

This entry is part 9 of 21 in the series SPServices Stories

Introduction

Here’s another SPServices Stories post that is a bit older and talks about how you can use SPServices with other popular plugins and frameworks. While this is possible with the CSOM, I’ve always found that SPServices provides a much tighter and more controllable syntax. You probably can’t trust me on that, though, since I wrote it.

Phil Harding’s post from March 2012 called SharePoint: Developing with Client-side Technologies: jQuery, REST, SPServices and JsRender caught my eye because in it he explains how he used the popular JsRender with SPServices. Many people want to use rendering frameworks in general or specifically in conjunction with SPServices, and JsRender has been a popular choice. Knockout,js is probably becoming more popular, but JsRender still has its place. You should evaluate the options based on your own business requirements to decide what’s best for you.

Keep in mind that is doesn’t really matter what version of SharePoint you’re working with, as these techniques can work well with SharePoint 2007, 2010, and 2013.

Phil Harding (@phillipharding) is an independent SharePoint consultant from Manchester, UK, specializing in development for the 2007, 2010 and (he’s hoping really really soon) 2013.

Developing with Client-side Technologies: jQuery, REST, SPServices and JsRender

Having recently been immersed in developing client-side functionality for a SharePoint 2007 project I thought I’d share some of the techniques and tools I’ve used in doing so.

The functional requirements in this project are pretty standard CRUD operations;

  1. Collect data from the user and create new list items
  2. Display and modify existing data
  3. Display formatted lists of existing data

In this post we are going to retrieve a set of list items from a SharePoint list and display that data using a technique very similar to that used by ASP.NET data bound/templatized controls.

SPServices.

The premier tool IMHO for interacting with SharePoint 2007 from the client is the SPServices library by @sympmarc, check out the documentation as the library is pretty extensive.

Here we will be using the SPServices GetListItems method which wraps the SharePoint Lists web service.

REST.

If you’re working with SharePoint 2010, you might also consider using the REST interface for retrieving data, although this interface by default returns XML, it can also be configured to return JSON, and the jQuery getJSON() method does exactly that by configuring the $.ajax() call to the REST interface appropriately. Why JSON? Well as with SPServices, using JSON encoded results fits very nicely when using jsRender to render your output markup. Some good examples of how to use the REST interface can be found here.

[important]Ed: Note that as of v0.7.1, SPServices contains a function called $().SPXmlToJson which makes it a no-brainer to convert GetListItems results to JSON.[/important]

Choosing a Client Side Data Retrieval Interface

If you’re using SharePoint 2007, your options are (very) limited. By limited I mean, that pretty much your only sane option is SPServices, there are other options of course, 2007 has the [SOAP] List webservice which you could grok against – you’ll have to write a lot of javascript if you want to go that route, but seriously, why bother, SPServices has you more than covered.

If you’re using SharePoint 2010 or 2013, you’ve got the JSOM interface which you can use to read list data, frankly though, given the amount of code you have to write just to read some data, I almost never use the JSOM for this.

SPServices of course is a valid choice to make – as with all things choose the right tool to accomplish your goal. Personally, I tend to use REST when my data needs are typically one-way, i.e. reading, even then I may defer to SPServices if my query is sufficiently complex – the REST interface is pretty damn flexible but it won’t allow you to model complex queries in the way that CAML does.

For updating data back to lists, again you can use REST, JSOM or SPServices. For me, I might typically use JSOM to update list items, sure I can do this using REST, but to do this you’ll have to manage the ETag – another piece of state to maintain (see the Concurrency Management section for more information). I also came across a javascript library recently called data.js, which seems to be a wrapper over OData services, I haven’t used it yet but it definitely looks interesting.

Finally, SPServices has the UpdateListItems method which serves both creating and updating data.

jsRender.

Having retrieved your data from SharePoint, you could of course, write quite a bunch of grungy JavaScript and DOM code to create the rendered display, however there is a much better way, and that is to use something latterly called jQuery Templates, which, like ASP.NET data-bound or templatized controls, allows you to write the markup template for your output and include bits which bind to the data being displayed.

jQuery Templates are officially deprecated in favour of a new but similar technology called jsRender by Boris Moore.

jsRender seems to be gaining a lot of traction and there is a growing amount of information available out there, and the documentation provided by Boris is more than enough to get you going.

Retrieving List Items.

So lets get going, first we’ll write the SPServices code to retrieve a set of list items, which we’ll then iterate over and place into an array of JSON objects (required by jsRender).

function GetListItemData() {
  var container=$('#container');
  $(container).html("");

  // get list data
  var datarows = [];
  $().SPServices({
    operation: "GetListItems",
    webURL:"http://sp2007/sites/demo",
    async: false,
    listName: "The List Title",
    CAMLViewFields:"",
    CAMLQuery:"........",
    completefunc: function(xData, Status) {
      $(xData.responseXML).SPFilterNode("z:row").each(function() {
        var x={
          title: $(this).attr('ows_Title'),
          id: $(this).attr('ows_ID'),
          reviewoutcome: $(this).attr('ows_ReviewOutcome')
        };
        datarows.push(x);
      });
    }
  });
  ..... // display list data
}

Here we use SPServices GetListItems to retrieve the data, amongst other things we supply the following parameters;

  1. operation: “GetListItems”
  2. Optional webURL parameter, if not supplied SPServices will use the equivalent of SPContext.Current [the current Web]
  3. listName: “The List Title”
  4. CAMLViewFields: the list of fields we want returned by the query
  5. CAMLQuery: the CAML query in the form; “<Query><Where>….</Where><OrderBy>….</OrderBy></Query>”

I also specify a completion function which parses and iterates over the returned rows, creates a JSON object and adds it to an array.

Note: SPServices also provides the SPXmlToJson function which will convert the returned rows to an array of JSON objects.

Next we’ll use jsRender to display the data we just retrieved using the supplied template (#reviewTemplate), in this case the template with id reviewTemplate.

function GetListItemData() {
  var container=$('#container');
  $(container).html("");

  var datarows = [];

  ..... // get list data

  // display list data
  if (datarows.length > 0) {
    $(container).html( $("#reviewTemplate").render(datarows) );
  } else {
    $(container).html("There are no items to display.");
  }
}

The return value from jsRender is then set as the html value of a container DIV or other element.

jsRender Templates.

So what’s a jsRender template? Quite simply it is a <SCRIPT /> block with an ID value and a type set to text/x-jsrender, as shown below.

<script id="reviewTemplate" type="text/x-jsrender">
<TABLE cellSpacing="0" cellPadding="0" width="100%">
  <TBODY>
    <TR>
      <TD style="width:400px">
        <A title="{{:title}}" href="{{:~reviewurl(id)}}">{{:title}}</A>
      </TD>
      <TD style="width:20px">
        {{outcome reviewoutcome /}}
        {{if reviewoutcome=='Undecided' tmpl='#reviewundecided' /}}
        {{if reviewoutcome=='Accepted' tmpl='#reviewaccepted' /}}
        {{if reviewoutcome=='Rejected' tmpl='#reviewrejected' /}}
      </TD>
    </TR>
  </TBODY>
</TABLE>
</script>
<script id="reviewundecided" type="text/x-jsrender">
  <IMG style="" title="this is undecided." border="0" src="http://sp2007/_layouts/images/erg-0.gif" />
</script>
<script id="reviewaccepted" type="text/x-jsrender">
  <IMG style="" title="this was accepted." border="0" src="http://sp2007/_layouts/images/erg-2.gif" />
</script>
<script id="reviewrejected" type="text/x-jsrender">
  <IMG style="" title="this was rejected." border="0" src="http://sp2007/_layouts/images/erg-1.gif" />
</script>

Here we’re showing 4 jsRender templates, reason being that a feature of jsRender allows you to use template composition, i.e. to use different templates to render different parts of the output. In this case we have 3 different templates to render an <IMG…/> element according to the value of the “reviewoutcome” object property (which is the listitems ows_ReviewOutcome column value). To summarise whats going on I’ll briefly describe each of the jsRender features we’re using;

Expression Evaluation / Output an Object Property Value

Use the {{:  expression  }} tag to evaluate an expression or output the property value of the current item, this form does not perform HTML encoding of the output

Use the {{> expression  }} tag to evaluate an expression or output the property value of the current item, this form performs HTML encoding of the output

Call a Custom Helper Function

Use the {{:~ customhelper(expression)  }} tag to call a custom helper function that you have written, which optionally accepts parameters, and returns the desired output – in the sample above we created a helper function called reviewurl to build a composite HREF value for an <A /> element.

See below for help writing a custom helper function.

Conditional Processing : If/Else

Use {{if  expression }}…{{/if}} {{else  expression }}…{{/else}} tags to perform conditional processing or branching of the template – in the sample above we used conditional processing to choose a different jsRender template to build <IMG /> elements based on the value of the current items reviewoutcome property value.

Call a Custom jsRender Tag

In the above example we used conditional processing to chose a jsRender template to display different <IMG /> elements, another method of doing this is to write a custom jsRender tag which will do the same thing. To use a custom jsrender tag you have written, use the following form {{mytagname expression /}}. In the sample above we created a custom tag called outcome which accepted the reviewoutcome property value of the current item and returned an <IMG /> element.

See below for help writing a custom tag function.

To create a custom helper function;

A custom helper function, as you might imagine, is simply a JavaScript function which optionally accepts parameters and returns something for display. Usefully the function can reference global variables in the page, as you can see I’m referencing global variables g_rlid and g_thispageurl.

/* jsRender helper function */
$.views.helpers( {
  reviewurl:function(fid) {
    var m="mypage.aspx?";
    m+="form=Display";
    m+="&list="+g_rlid;
    m+="&id="+fid;
    m+="&Source="+g_thispageurl;
    return m;
  }
});

To create a custom jsRender Tag function;

A custom tag function, is also a JavaScript function which optionally accepts parameters and returns something for display.

/* jsRender custom tag */
$.views.tags({
outcome: function(value) {
var ret='';
switch(value) {
case 'Undecided':
ret="<IMG style='' title='' border='0' src='http://sp2007/_layouts/images/erg-0.gif' />";
break;
case 'Accepted':
ret="<IMG style='' title='' border='0' src='http://sp2007/_layouts/images/erg-2.gif' />";
break;
case 'Rejected':
ret="<IMG style='' title='' border='0' src='http://sp2007/_layouts/images/erg-1.gif' />";
break;
}
return ret;
}
});

Putting all this together we get something that is ripe for a little CSS beautification.

http://platinumdogs.files.wordpress.com/2012/03/sps-01.png

There’s much more to go at in jsRender, including some interesting effects involving hoverstate and re-rendering of item display using dynamic templates. Hopefully the documentation (and feature-set) will continue to improve and that this post has provided a leg up should you wish to start using it.

Series Navigation<< SPServices Stories #8 – CEWP, Nintex, jQuery, SPServices and the Client APISPServices Stories #10 – jqGrid Implementation Using SPServices in SharePoint >>

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.