The other day I was talking to one of my colleague John Holah about retrieving large amounts of data from a SharePoint 2010 Lists using “client-side” v “OOB” techniques for a particular client, who has set use a number of challenges/limitations:
- Our access is limited to Site Collections
- We cannot deploy server-side code
- Internet Explorer 8 is used by all of client’s employees (120,000 Users globally)
Depending on what the end goal, previously we used these techniques to retrieve data:
- CQWP* and write custom XSL to render the content as HTML
- Call a SharePoint web service using a JavaScript library call SPServices and
- populate an array or an object before rending it as HTML
Option 1: is relatively quick to implement, however it has a number of limitations:
- The source of the content is limited to either a Content Type or a List
- In my opinion, it is not as easy to apply logic to XSL as it is to JavaScript
- IE8 times-out if a large number of rows are rendered to the UI (this can vary depending on the number of columns as well as rows and the complexity of the HTML)
Option 2: is has flexibility, however:
- A call to a web service is not as efficient as the CQWP in retrieving data.
- A significant number of lines of code needs to be written to call web service (particularly if it’s asynchronous)
- Supporting custom code is time consuming as developer coding styles and techniques vary
So what if we combined the two techniques? Would we get the rapid development of the CQWP and flexibility SPServices? Well I’ll let you decide after I show you some code:
Step 1
As preparation create a new list called “Product Relationships” and add the following columns:
Column Type ----------------------------------------- Product1 Number Product2 Number
And add some items, for example:
Product1 Product2 ------------------------------------------ 2 13 6 2 13 14 15 16 18 19 20 18 20 19
Step 2
Add a CQWP to a page, configure it to point to your new list and export (save to your local machine for editing).
Step 3
Add the following directory structure to the “Style Library” directory of you site collections root sites:
\Branding\XSL\MyWebpart
And upload the MyWebpart.wepart file having add the reference (path) to the XSL file (you will create shortly):
- ItemXslLink
- MainXslLink
- HeaderXslLink
And then edit the element called “Xsl”.
Once completed the file should look something like the following:
Step 4
Create a copy of the ContentQueryMain.xsl file located in “\Style Library\XSL Style Sheets\” and edit it so that it looks something like this:
The lines of code to look at in detail starting from the top are:
<script />
The tag referencing the “_temp.js” file, this would normally be placed in the master page, however for the demo it is here.
<div id="relationshipEditor">…</div>
Used by the JavaScript to inject the demo content.
<script>…</script>
Wraps around the XSL template which will populate a JavaScript Array.
var pr = SJLewis.ProductRelationships;
Creates is a shortcut to a JavaScript Namespace.
<xsl:call-template name="populateArray" />
Does what is says, called the populateArray template.
<xsl:for-each select="$Rows">…</xsl:template>
Loops through the list items.
pr.productRelationships.push(new pr.productRelationship(…));
The “new pr.productRelationship(…)” code creates a new object containing data from the list item. And “pr.productRelationships.push()” add the object to the array.
pr.doSomeStuff();
Is a function that loops though the array and added the content to the page.
Step 5
Create a new JavaScript file for called “_temp.js” and add the following code:
And upload to this directory:
/MySiteCollction/Style Library/Branding/HTML/MyWebPart/_temp.js
Step 6
Reload the page and as baring no errors you page may look something like this:
Test 20 - 20 Test 20 - 20 Test 18 - 18 Test 15 - 15 Test 13 - 13 Test 6 - 6 Test 2 – 2
This model could easily be extended to retrieve data from multiple Content Types or Lists by adding more CQWPs and then exposing more objects and arrays from the “SJLewis.ProductRelationships” namespace. And instead of each CQWP calling the “doSomeStuff()” function to populate a DIV tag, they could call a “trigger()” function that informed a custom event handler when the data is loaded and ready for processing (e.g. combined, filtered and displayed by a div exposed by a CEWP).
XSL / JSRender Trap (Updated 14/07/2014)
When adding properties to a HTML tag located within your CQWP’s XSL file, which the value will be populated by JSRender, be sure to escape the curly braces like this:
Otherwise the XSL parser will strip the {{attr:ID}}} from the tags properties and the HTML will be rendered like this {attr:ID}.
CQWP Cashing(Updated 16/07/2014)
Can’t see your new data and you need to see it immediately? Sounds like you need to turn off Caching. To do this, export the webpart and edit the property called “UseCache” by changing its value to “False”. The result should look like this:
Next save the webpart file and upload to your “Web parts” gallery and the final step is to replace the original webpart with using your new definition.
Glossary of terms:
- CQWP: Content Query Webpart
- CEWP: Content Editor Webpart
- OOB: Out of the box