SPTechCon San Francisco 2013 Wrap Up

Well, I’m back in the snowy Northeast after a great four days at SPTechCon San Francisco 2013. As always, the BZ Media folks put on a great show. SPTechCon is consistently well-run and packed with excellent content, vendors, and attendees.

I wanted to post links to the slide decks from my three sessions. They are available on SlideShare.

If you weren’t at SPTechCon or you were there and missed this session, I’ll be doing it again for the MetaVis SharePoint MVP Webinars Series on Wednesday, March 13, 2013 from 2:00 PM – 3:00 PM EDT. You can register here. The webinar will also be recorded for later viewing.

In addition, as I promised in my third session, here’s a link to a WSP which contains the demos I showed. The WSP is simply the Office365 site saved as a template. In the past, some people have had difficulty instantiating my demo templates in their environments due to activated features not matching. (My rants on the lack of  true portability of SharePoint-based content will probably continue, like Trials and Tribulations: Migrating My Demos Site to Office365, Office365 SharePoint Online Portability Issues Strike Again, and Moving Lists from Hosted WSS 3.0 to Office365 – The ShareGate Way.) If you run into this sort of issue, let me know in the comments and we’ll see what we can work out.

SPServices 2013.01 Is Underway – Learnings Ensue

I’ve started really cranking on the new version of SPServices and I’m having a blast, as usual. I’ve learned a few things already, and I thought I’d capture them in a post.

“use strict”;

Just gotta do it. I balked at implementing this previously, as it kept hating my code. Well, it hated my code for a reason. "use strict"; makes you fix some pretty dumb mistakes, and I had quite a few of them. SPServices ran just fine with those mistakes, but by implementing "use strict";, they aren’t even there anymore.

If you want to understand why "use strict"; is a good idea with jQuery, read John Resig’s post ECMAScript 5 Strict Mode, JSON, and More.

JSLint vs. JSHint

JSHintAs part of my refactoring and housecleaning. I went to run SPServices through JSLint as I usually do. It seems that Douglas Crockford, godfather of JavaScript and author of JSLint, has introduced what amounts to either an annoying new feature or a bug into JSLint. I saw the message “Use spaces, not tabs.” on so many lines that JSLint only was making it through about 1% of my code before giving up.

There’s a post over on StackOverflow called New JSLint errors “use spaces, not tabs” and “unsafe character” wherein someone has tracked down what’s going on. I like using tabs in my code, so I took the hint and the advice in the post and headed over to JSHint instead.

It turns out that JSHint does some nice things that JSLint doesn’t do, anyway. Each message shows the line number as a link which takes you into the code at the proper spot to fix it right there. With JSLint, I was always copy/pasting back and forth to SharePoint Designer to make my fixes. JSHint also color codes your code in the edit window so that you can really do editing. Very nice. The only drawback is that JSHint throws an error when I try to run it in IE9, but I’m fine with working in Firefox.

Refactoring

Every single time I go through SPServices, I do a lot of refactoring. I’m a learning human, and each time I know more (at least I like to think I do) about good coding practices than the last time. Sometimes I really want to slap myself up side the head seeing what I did in some of my earliest efforts. I’m taking this opportunity to refactor things yet again, creating many more complex objects to store things than I had originally. This is a good thing, not a complicating thing, as it will make the code far more manageable and readable over the long haul. (Yes, there is a long haul. SPServices still has a good number of years in it, IMO.)

I’m also taking advantage of some of the SharePoint 2010 context information which is available in JavaScript variables (if we’re in 2010, of course, with nice fall back for 2007). Thanks to John Liu’s post SharePoint – JavaScript current page context info which gave me the impetus for this.

Version Numbers

You may have noticed that I’ve switched my version numbering scheme. I have been confusing myself with the version numbers over the last year or so. On one level I wanted to sort of align with the jQuery version numbers, and on another I was being coy and avoiding ever getting to version 1.0. (I’m asymptotic in my tendencies.)

With this version, I’ve switching the versing scheme altogether. This next version will be 2013.01, meaning the first version in 2013. It moves things away from the jQuery alignment and still is an increasing function, so it should make everyone happy. Except the people who will complain about it.

OK, enough chit chat. Back to work. Mark Miller and I are working on some magic and hijinks for his keynote next week at SPTechCon in San Francisco. Hope to see you there!

SPServices Stories #10 – jqGrid Implementation Using SPServices in SharePoint

Introduction

Today’s SPServices Story comes from Prateek Kulkarni in Bengaluru, India. Prateek posted this originally on the C# Corner site as jqGrid Implementation Using SpServices in SharePoint.

As with several of the earlier SPServices Stories posts, I found this one interesting because it shows how to use SPServices with another framework to render the results obtained from the Web Services calls.

I’ve had several people tell me that there isn’t enough “story” to these SPServices Stories. Have a better one? Let me know!

jqGrid with SPServices

This article is regarding implementation of jqGrid(demo) using SPService(CodePlex)

SPService is a jQuery library which abstracts SharePoint’s Web Services and makes them easier to use. It also includes functions which use the various Web Service operations to provide more useful (and cool) capabilities. It works entirely client side and requires no server installation.

Use of SPService and jQuery is best explained at Marc’s blog.

Following Js files are needed for JqGrid Implementation with SPService

  • jquery-1.8.2.js
  • grid.locale-en.js
  • jquery.jqGrid.min.js  // Structuring jqGrid
  • json2-min.js  // Parsing data to json format
  • jquery.SPServices-0.7.2.js  // For getting the list items

Css file required

  • ui.jqgrid.css  //Style sheet of Grid

HTML controls for jqGrid are as mentioned below.

<div id='tblMain' style="float:left">
  <table  id="list" ></table>
  <div id="pager" style="text-align:center;"></div>
</div>

Loading JqGrid on the page load:

jQuery("#list").jqGrid({
  datatype: GetMyData,
  colNames:["Project ID","Project Name","Delivery Manager","ApprovalStatus"],
  colModel:[{name:'ProjectId',index:'ProjectId',align:'left',sortable: true},
            {name:'ProjectName',index:'ProjectName',align:'left',sortable: true },
          {name:'DeliveryManager',index:'DeliveryManager',align:'left',sortable:true},
          {name:'ApprovalStatus',index:'ApprovalStatus',align: 'left',sortable: true }
                       ],
  pager: true,
  pager: '#pager',
  pageinput: true,
  rowNum: 5,
  rowList: [5, 10, 20, 50, 100],
  sortname: 'ApprovalStatus',
  sortorder: "asc",
  viewrecords: true,
  autowidth: true,
  emptyrecords: "No records to view",
  loadtext: "Loading..."
});

In the above jqGrid load function I have mentioned the datatype for the grid as GetMyData() which is a function that gets triggerred first.

The GetMyData method has function GetDataOnLoad which uses the SpServices which has the basic operation of getting the list items i.e. GetListItems, which need optional CAML Query property which will fetch the data from list with some WHERE clause.

In the code I have a list called ProjectDetailsList which will contain details of some projects which are inserted by some Project Manager or delivery manager. So the requirement was when a user log in to the system I should get the current login user name and pass the same user name to the “where” clause of query so the grid will contain data of projects to which the current logged in user is assigned as PM or DM.

To get the current login user am using SpServices Operation SpGetCurrentUser.

The method GetTheOrderByType function will make the query part for SpServices.

The functions code is as follows:

function ForGettingUserName() {
  var userName = $().SPServices.SPGetCurrentUser({
      fieldName : "Title",
      debug : false
    });
  return userName;
}

function GetMyData() {
  sortIdexName = jQuery("#list").getGridParam("sortname"); //Maintaining Consitant SortName after the Sortcol event
  sortOrderName = jQuery("#list").getGridParam("sortorder"); //Maintaining Consistant Sort Order
  Query = GetTheOrderByType(sortIdexName, sortOrderName);
  var CAMLViewFields = "<ViewFields>" +
     + "<FieldRef Name='projectName' /><FieldRef Name='projectID' />"
     + "<FieldRef Name='Title' /><FieldRef Name='deliveryManager' />"
     + "<FieldRef Name='projectSQA' /><FieldRef Name='approvalStatus' />"
     + "<FieldRef Name='projectStartDate' /><FieldRef Name='projectEndDate' />"
     + "<FieldRef Name='sqasiteurl' /><FieldRef Name='ID' />"
     + "</ViewFields>";
  GetDataOnLoad(Query, CAMLViewFields);
}
Function for Getting the Query Type and the particular WHERE CLAUSE TO send the Query to GetListItem function
function GetTheOrderByType(index, sortOrder, userName) {
  var OrderByType;
  if (index == "ProjectName") {
    if (sortOrder == "desc") {
      OrderByType = "<Query>" +
         + "<Where><Or>" + "<Eq>" + "<FieldRef Name='deliveryManager'/><Value Type='Text'>"
         + userName + "</Value>" + "</Eq>"
         + "<Eq><FieldRef Name='projectManager'/><Value Type='Text'>"
         + userName + "</Value></Eq>" + "</Or></Where>" +
         + "<OrderBy><FieldRef  Name='projectName' Ascending='FALSE' /></OrderBy>" +
         + "</Query>";
    } else {
      OrderByType = "<Query>" +
         + "<Where><Or>" + "<Eq>" + "<FieldRef Name='deliveryManager'/><Value Type='Text'>"
         + userName + "</Value>" + "</Eq>"
         + "<Eq><FieldRef Name='projectManager'/><Value Type='Text'>"
         + userName + "</Value></Eq>" + "</Or></Where>" +
         + "<OrderBy><FieldRef  Name='projectName' Ascending='FALSE' /></OrderBy>" +
         + "</Query>";
    }
  } else if (index == "ApprovalStatus") {
    if (sortOrder == "desc") {
      OrderByType = "<Query>" +
         + "<Where><Or>" + "<Eq>" + "<FieldRef Name='deliveryManager'/><Value Type='Text'>"
         + userName + "</Value>" + "</Eq>"
         + "<Eq><FieldRef Name='projectManager'/><Value Type='Text'>"
         + userName + "</Value></Eq>" + "</Or></Where>" +
         + "<OrderBy><FieldRef  Name='approvalStatus' Ascending='FALSE' /></OrderBy>" +
         + "</Query>";
    } else {
      OrderByType = "<Query>" +
         + "<Where><Or>" + "<Eq>" + "<FieldRef Name='deliveryManager'/><Value Type='Text'>"
         + userName + "</Value>" + "</Eq>"
         + "<Eq><FieldRef Name='projectManager'/><Value Type='Text'>"
         + userName + "</Value></Eq>" + "</Or></Where>" +
         + "<OrderBy><FieldRef  Name='approvalStatus' Ascending='FALSE' /></OrderBy>" +
         + "</Query>";
    }
    return OrderByType;
  }

  //This function gets the data from List using SpServices
  Function GetDataOnLoad(Query, CAMLViewFields) {
    $().SPServices({
      operation : "GetListItems",
      async : false,
      listName : "ProjectDetailsList",
      CAMLQuery : Query,
      CAMLViewFields : CAMLViewFields,
      completefunc : processResult
    });
  }

The processResult is the function which formats the data which can be converted to Json and adds to the JqGrid.
The reason of formatting of data in the following particular format is to make it readable by the Json parser which is json2.js file. I had implemented the same JqGrid in asp.net application with AJAX calls where it was returning the data in this format and some other bloggers also used the same data format in the MVC or asp.net application with the help for JsonHelper class which mainly formats the data returned from the DB

//Processing the XML result to formatted Json so that We can bind data to grid in Json format
function processResult(xData, status) {
  var counter = 0; // Gets the total number of records retrieved from the list (We can also use xData.ItemCount method for counting the number of rows in the data )
  var newJqData = "";

  $(xData.responseXML).SPFilterNode("z:row").each(function () {

    var JqData;
    if (counter == 0) {
      JqData = "{id:'" + $(this).attr("ows_projectID") + "',"
         + "cell:[" + "'" + $(this).attr("ows_projectID") + "','" +
        $(this).attr("ows_projectName") + "','" +
        $(this).attr("ows_deliveryManager") + "','," +
        "]}";
      newJqData = newJqData + JqData;
      counter = counter + 1;
    } else {
      var JqData = "{id:'" + $(this).attr("ows_projectID") + "',"
         + "cell:[" + "'" + $(this).attr("ows_projectID") + "','" +
        $(this).attr("ows_projectName") + "','" +
        $(this).attr("ows_deliveryManager") + "','," +
        "]}";
      newJqData = newJqData + JqData;
      counter = counter + 1;
    }

  });
  FinalDataForGrid(newJqData, counter);
}

That’s it. Add the data to the grid with the div control and the other page number calculation is for showing the pager.

function FinalDataForGrid(jqData, resultCount) {
  dataFromList = jqData.substring(0, jqData.length - 1);
  var currentValue = jQuery("#list").getGridParam('rowNum');
  var totalPages = Math.ceil(resultCount / currentValue);
  var PageNumber = jQuery("#list").getGridParam("page"); // Current page number selected in the selection box of the JqGrid
  //formatting rows
  newStr = "{total:" + '"' + totalPages + '"' + "," + "page:" + '"' + PageNumber + '"' + ","
     + "records:" + '"'
     + resultCount + '"' + ","
     + "rows:"
     + "[" + dataFromList + "]}";
  var thegrid = jQuery("#list")[0];
  thegrid.addJSONData(JSON.parse(newStr)); //Binding data to the grid which is of JSON Format
}

And the grid works fine and fast on paging, sorting and also even search, we can make the particular column as hyperlink which I will blog in the next part. Sample grid is as follows and this grid has some extra columns then the mentioned in above code

SPServices Futures: Moving to jQuery’s Deferred Objects and More

As I gear up to work on the next release of SPServices, I want to make some pretty fundamental changes/improvements to the internal plumbing. What I’m hoping to do with this post is to gather any ideas and feedback that the user community has about the implementation before I go too far with things.

SPServices

Deferred Object and Promises

In all prior versions, we’ve relied on the completefunc (which I made up) to process the results we get back from a Web Services operation call. In the meantime, jQuery has moved forward significantly.

In jQuery 1.5, we got the first deferred object capabilities. I was loathe to change the internal workings of SPServices at the time because we had a substantial user base, even then.

Now the user base is significantly larger (as of this writing, there have been almost 75,000 [!] total downloads), but I think it’s time to add the deferred capabilities into the core SPServices function. More and more people have been exposed to deferred processing capabilities in script at this point, so it will be less of a shock to existing SPServices users (I hope!).

Oddly, I’ve only had one request (at least that I can remember) to add deferred processing into SPServices. It came from a Codeplex user named MgSam in a thread s/he titled JQuery Deferred compatibility, and I’ll admit that I blew it off a bit when he raised it as a possibility.

My strongest impetus for considering this fundamental architecture shift is having seen Scott Hillier talk several times about Utilizing Promises in SharePoint 2013 Apps. In actual fact, his talk applies to JavaScript (and thus jQuery) development more than it applies to SharePoint 2013 development. We can use the deferred methodology even if we’re running our scripts on SharePoint 2007. It’s a way to manage requests in the script and has little to do with the version of SharePoint.

In doing this, my goal will be to keep full backward compatibility so that all existing code continues to function with no changes, but I may deprecate the current completefunc focused methodology, either in this next release or shortly thereafter.

in the simplest form, it will look something like this (borrowing from MgSam’s example in the thread above):

function myCode(someOtherListId) {
    /* Ideally, I should be able to do this call SPListNameFromUrl asynchronously
     * as well, perhaps add an optional "async" parameter
     * which, if used, returns the jqXHR object and invokes
     * a callback upon completion rather than blocking until
     * the data returns. This is not the main point of this code though.
     */
    var currentListId = $().SPServices.SPListNameFromUrl();

    //Call 1
    var a = $().SPServices({
        operation: "GetListItems",
        async: true,
        listName: currentListId,
        completefunc: function(xData) {
            //Do something useful
        }
    });

    //Call 2
    var b = $().SPServices({
        operation: "GetList",
        async: true,
        listName: currentListId,
        completefunc: function(xData) {
            //Do something useful
        }
     });

     //Call 3
     var c = $().SPServices({
        operation: "GetListItems",
        async: true,
        listName: someOtherListId,
        completefunc: function(xData) {
            //Do something useful
        }
     });

     /* Now I want to do something once all 3
      * asynchronous calls have completed. Under the current
      * model, there's no easy way to do this.
      * I either have to hand-roll some ugly code,
      * or contort my completefuncs so that they work with
      * jQuery's Deferred.
     */
}

Moving toward the deferred object approach will also mean that I’ll replace the simplistic caching mechanism I put into place using the .data() function in v0.7.2. There will be no visible difference in the way it works, but the underlying mechanism will be deferred promises instead.

SharePoint 2007

I’m also considering finally ending development specifically for SharePoint 2007. I’ve continued to use WSS 3.0 as my development environment since the first release of SPServices so that I can “test up” rather than down *and* up.

I still have a lot of people contacting me with questions who are using SharePoint 2007. In fact, some of my best clients are still on SharePoint 2007. It’s still a great platform that works well for many people who are still using it.

That said, there are some capabilities in SharePoint 2010 and now SharePoint 2013 that I haven’t tried to take advantage of because they aren’t there in SharePoint 2007. It isn’t that I want to abandon the SharePoint 2007 folks, but I’m considering making the main focus SharePoint 2010.

I’m very interested in hearing people’s thoughts on that. There’s no easy way for me to know what versions everyone out there has, so chime in.

Version Numbering

These changes will definitely merit a more significant version bump than just going from 0.7.2 to 0.7.3, of course. Is it finally time to ship a 1.0.0? Or maybe I should just decide to go to 5.3.8 or something. The numbers mean nothing, of course, as long as they go in a consistent direction. I’m even toying with 2013.01. Any thoughts on this?

Thanks to everyone out there who uses SPServices, especially those of you who have contacted me to let me know how it has helped you accomplish your business goals. If you have a story to tell, please consider writing it up for my SPServices Stories series. I’m planning to keep that series going as long as there are good stories to tell.

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

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.