SharePoint

More customizations with Client Side Rendering

Recently I posted about how you can use Client Side Rendering (CSR) to display contacts on a map.  After posting about how to display the entire list data, I decided I wanted to see how CSR could  be used to change the user experience while adding, updating, and viewing list items, updating items, and viewing items.  This post will provide a high level overview of how I was able to change the display during New, Display, and Edit of an individual item and then later I will actually put this together with the Contact Map idea.

Where’s the Documentation?

As mentioned in the previous blog, this work was all pretty much done 100% in the dark.  I was able to find a few blogs about how to style specific fields, in particular those custom fields being added by a feature, but there really isn’t much about the full CSR capabilities.  In order to figure some of this stuff out I ended up using the IE Developer Tools Console to view various objects, in particular the SPClientTemplates.TemplateManager and SPClientTemplates._defaultTemplates JavaScript objects.

Specific Items mean Specific Field(s)

My original goal was to do something, really anything, with all the input fields.  However, to date, I haven’t been able to figure out how to get my CSR to change all the fields, but I have been able to impact specific field(s) and in the remainder of this post I will focus on impacting my custom field ‘Lat’.  This being said, the CSR does include a OnPostRender function which you can use to ‘go back’ and update the fields, but it doesn’t do anything while the field is being rendered.

CSRs need to self execute, and to prevent namespace pollution I’m using the self wrapping anonymous function.

(function() {
})();

We will again use the overrideCtx and overrideCtx.Templates objects to specify the various items we want to control.

var overrideCtx = {};
overrideCtx.Templates = {};

Unlike our Contacts on a List example this time rather than overriding the Item template we are going to override the Fields.  Fields is a bit different from the item in that rather than providing a function which is passed a context object, Fields is an object that specifies the field(s) we want to override during render.  For each field specified we can then provide our rendering template function which receives the current Field’s context.

overrideCtx.Templates.Fields = {

‘Lat’: {

‘NewForm’: function(ctx) { return (“<div style=’border: 1px solid blue;’>Hello World</div>”); }
‘EditForm’: function(ctx) { return (“<div style=’border: 1px solid green;’>Hello World</div>”); }

}

};

Initially, the names ‘NewForm’ and ‘EditForm’ which match up with the URL /NewForm.aspx and /EditForm.aspx caused me to assume the naming’s should use the name of the ASPX form.  However, ‘DispForm’ (/DispForm.aspx) did not provide the expected rendering and this is where the IE Developer Tools were critical.  Using the IE Developer Tools and the Console I was able to look at the SPClientTemplates._defaultTemplates where I was able to traverse the object structure and found the function ‘DisplayForm’.

Related

SharePoint Contacts on a Map with Client Side Rendering

Advertisements

SharePoint Contacts on a Map with Client Side Rendering

Several years ago, back in the dark days of SharePoint (MOSS) 2007, Tom Resing and I worked together on a demo displaying contacts from a SharePoint contact list on a Bing/Google Map.  He and I presented this at several SharePoint Saturday events (Boston, Virginia Beach, Richmond, Tampa) and found highly positive response.  It has been a while since Tom and I worked together, and a lot has changed in SharePoint so I wanted to revisit our old demo and take a newly available approach.

SharePoint 2007 & 2010

When Tom and I first worked together jQuery was early in development, HTML5 was only being discussed, and Chrome didn’t exist.  JavaScript was used a little, but because of the browser limitations it didn’t have the capabilities it has today, so SharePoint relied heavily on XML and XSLT to edit and customize the display of information.  The demo was remarkably simple but required significant work with XSLTs.  We would do the demo in SharePoint 2007 by adding a SharePoint DataView Web Part (DVWP) and customize the XSLT list and item rendering to add the map and geocode the items.  This worked well, but injecting JavaScript through an XSLT translation required HTML encoding of symbols like ‘&’ and ‘>’ which really made the JavaScript code very difficult to read and understand.

History Lesson: You can find Tom’s old slide deck here.

SharePoint 2013 – Client Side Rendering (CSR)

Today jQuery is a mature, and a common tools set, HTML5 is becoming more and more common, and business applications rely on JavaScript almost as much as Server Side code.  SharePoint 2013 introduced a new method, utilizing JavaScript, to provide rendering of lists rather than using the ‘old’ method of XSLT.  Given this improvement, I thought it was worthwhile to revisit the old demo, and give it a refresh.

Updated Demo

I have been unable to find a solid MSDN CSR API reference, but I can tell you CSR does NOT use the JSOM when executing so no need to perform context loads, queries, etc.  CSR actually seems to provide a JavaScript object that is a JSON’ized version of the List View and Rows so we can actually access row columns by using .[Static Row Column Name].

I’ve created a separate page where I could work with the list data and CSR to ensure I would be able to access my list even if the JavaScript wasn’t working and I would highly recommend others do the same at least during development.  Once your done developing, the CSR can be applied directly to a list/list view.  Also, on the page I added the Bing and jQuery references using a Script web part because I found that adding it in the CSR code did not guarantee that those files would actually be loaded.

From all the code examples I have seen, and JavaScript best practices, CSR files should have a self contained object so your variables and functions do not pollute the global namespace.  However, your CSR must be self executing, so begin with something like:

(function() {
})();

Now we need to create the Template Override object.  This object will be provided to and used by SharePoint to implement the rendering of the list and list items based on what areas we choose to override.

var overrideCtx = {};
overrideCtx.Templates = {};

Our template has to perform three main tasks:

  1. Add a Div that the Bing Map API can use to display the map tiles
  2. Capture each item in the List
  3. Initialize the map and add the geocoded items to it

In order to perform these task we will override the Header, Item, and OnPostRender.

One really nice aspect of the CSR is we can either call JavaScript functions, or we can return back HTML for rendering.  In the Header function we will just return the necessary HTML to add our div which the Bing API will use to display it’s map.  Add the following to override the Header

overrideCtx.Templates.Header = function(ctx) {

 return (“<div id=’mapDiv’ style=’position: relative; width: 450px; height: 450px;’></div>”);

 }

Next we want to capture each item in our list.  Because we don’t have the Bing Map loaded yet we will just store the items so once the Map and Search Manager are loaded we can the perform the geocoding and rendering.  To override our Items use the following:

overrideCtx.addressArray = new Array();
overrideCtx.Templates.Item = function(ctx) {

overrideCtx.addressArray.push({Title: ctx.CurrentItem.Title,
Address: (ctx.CurrentItem.WorkAddress + ” ” …)});

//This has been truncated for more efficient reading

}

Now that we have our Div and Items we can load the Map, Geocode the items, and add them to the display.  I’m going to avoid in depth discussion on how to work with the Bing Maps and Geocoding in this blog, but if you want more detail check out the Bing Map API.

To perform the initialization of the map and search I chose to use the OnPostRender, which ensures all other templating has been performed and is complete meaning everything I need to initialize and geocode is ready.

overrideCtx.OnPostRender = function () {

overrideCtx.Map = new Microsoft.Maps.Map(…);
Microsoft.Maps.loadModule(‘Microsoft.Maps.Search’, { callback: function() {


overrideCtx.geocodeRequest();

 }});

overrideCtx.geocodeRequest = function () {

$.each(overrideCtx.addressArray, function(index, val) {

var currentContact = {

where: val.Address,
callback: function (result, userData) {

var pushpin = new Microsoft.Maps.Pushpin(…);
overrideCtx.map.entities.push(pushpin);

},

};

});

}

Finally, now that our template is ready to be used we need to register it with SharePoint.  At the end of the self invoking function add:

SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);

Use Our CSR

With that our CSR is ready, now add the CSR js file to your site (I prefer to use the SiteAssets library because I’ve had issues in the past with Document Libraries not always returning the expected HTTP headers).  On a page with the Contacts List View (which should include the Address, City, State, and Zip fields) edit the List View web part and expand the Miscellaneous section.  There you will find a new text box ‘JS Link’ where you can add the url to your CSR file.  The JS Link field allows you to also use the ~site url token to make referencing your file easier and ensure the path is properly formatted for SharePoint to load.

Once you’ve added the CSR the your JS Link Save your changes and enjoy the new Client Side Rendering.

If your interested in my actual CSR JS file you can download it in PDF format here.

IE11 Broke SharePoint 2010

I’ve been noticing recently my SharePoint site was behaving oddly, especially when I wanted to edit a web part. Yesterday the odd behavior hit a critical point as I was unable to connect web parts on a page. The problem was every time I clicked the drop down arrow on the web part heading the page would refresh and some of the menu content would appear in a side panel, where the web part properties are usually displayed.

Knowing we had a customized master page I was convinced some change must have caused the problem. However, after reverting the master page to the site default the problem persisted. A coworker jokingly suggested I try using Chrome or Firefox. In frustration I opened the site in Firefox and amazingly everything worked.

I went back to IE 11 and opened the emulator setting. Although the browser mode was IE8 I noticed the User Agent setting was Default. I decided to change this to the IE8 User Agent setting and after the page refreshed, the site worked as expected.

After doing a little web search I found the IE team’s blog about changes to the User Agent string, which recommends you not use the User Agent Browser Sniffing technique (maybe something to tell the SharePoint Team?).

Overall, the site’s end user experience look unchanged, but it does effect the developer’s and site owner’s experience.

Site Collection Content Type vs. Content Type Hub

I’ve been working on a project recently that has a large number of sub-agencies and the parent organization was attempting to push a standardization of Content Types.  Since no one really wanted to duplicate work the organization decided they did not want to migrate content into SharePoint (from file shares) until all the content types and metadata had been identified and created.  However, as with all large agencies some groups wanted to move forward with limited or partial capabilities because after all some limited capability is better than what they currently have.  The concern that arose from this was: What if they created a Content Type in one of their Site Collections that had the same name as one that would be published later on?

The process I followed was very simple:

  1. Create a new Site Collection
  2. Create a Content Type ‘RFP’
  3. Create a Content Type in the Metadata Hub name ‘RFP’
  4. Publish and see what happens

Once the import of the Content Types was completed I checked my Content Type Import Log in the Site Collection (created in #1 above).  What I found was an error stating: Content Type Name ‘RFP’ conflict.  In addition I checked my Site Content Type and found that the one custom field I had added in the Metadata Hub was NOT included as a field of my local ‘RFP’ Content Type.

SharePoint Published Content Types

I have done a lot of development with SharePoint workflows, especially those developed in Visual Studio.  Unless I have been working with a standard list type, I generally create a Content Type that my workflow can be associated with and to ensure the columns and values needed in the workflow will be present.  However, creating Content Types is always a painful process, because as you develop the content types and test them you need to delete the original content type, and any list depended up in before you deploy the updated version.  This is even worse when you upgrade a solution that is in use in production because you can’t easily delete the content type just to add additional fields.

Recently, I have been working with Publishing Content Types, usually designed through the SharePoint UI, and what I began to notice was that when the published Content Type was updated in the Content Type Hub those changes were reflected in the sites making use of those Content Types.

This made me wonder if the same would happen if I deployed the Content Type through a Visual Studio solution, published it and then updated the Content Type.  I initially created a Content Type that had a Title and a Choice column.  Once deployed I published the content type and created a list in my Published Content Type Consumer site.  I then added an additional text column to the Content Type and redeployed.  After the Content Type Hub timer jobs executed the List I created using the Published Content Type now had the new column.

Lesson from this: If you have to deploy and maintain Custom Content Types use a Content Type Publishing Hub to manage the Content Types, and any future updates you may need to make.

SharePoint 2010 and jQuery 2.x

Recently, I was working with a coworker who had created a javascript dashboard using jQuery and KnockoutJS in SharePoint.  The dashboard had worked perfectly for him, but when I viewed the site none of the data would render.  While we were testing the site we noticed that my browser was running in Browser Mode IE10 with Document Standard IE 7 Standard, but his was running Browser Mode IE 10 with Document Mode: Standards.  Having battled with SharePoint 2010 using an HTML5 Masterpage I began looking for the Meta tag on the page which should define the appropriate browser mode and noticed he had removed it.  I had him add the tag back to the masterpage (from my experience removing the browser mode tag in SP2010 causes all kinds of issues when editing pages, list items, etc) but still found the dashboard was not functioning properly.

When we looked at the jQuery include I noticed he was using the latest version from the Microsoft CDN, which happens to be version 2.x.  Because I had another site running with jQuery and Knockout I had him revert his version of jQuery to 1.10.x and we found this was working.

The cause of the issue is detailed in the jQuery documentation for 2.x:
jQuery 2.x has the same API as jQuery 1.x, but does not support Internet Explorer 6, 7, or 8. (source)
The reason this is relevant is because SharePoint masterpages include:
<meta http-equiv=”X-UA-Compatible”content=”IE=8″/>
Which forces IE browsers to effectively run in an IE 8 mode.

Therefore, if you are a SharePoint 2010 developer and are attempting to use jQuery, make sure you are using 1.x versions

User Profile Personalized Links

Recently my company performed a migration for our old production environment to a new production environment so we had a more stable and robust platform to support the company, including providing leadership with better business intelligence about our operations. As part of the migration one of my goals was to launch My Sites for our internal users so they had somewhere to store information they were working on.

As I was thinking about what would be useful to our employees I ran across the Personalized Links capability available in the User Profile Service Application. In general this capability allows us to “push” links onto a user’s My Site. Since our company uses Great Plains for timecards and financial management integrated into SharePoint I thought it would be worthwhile to place the link to an employee’s Timecard Entry page along with a link to our primary portal. I then decided a link for Timesheet Reviewers made sense, but I didn’t want it to show up on all of the employee’s pages, just the employees who actually review timesheets. We have already scoped this link on our portal by using the Business Portal security groups, but since we are working in the context of the My Site we don’t have those security groups to rely on.

User Profile Personalized Links like most other things in SharePoint include the ability to apply audiences, so controlling who sees the links are possible, but I needed to create the right audience. I jumped over to the Profile Audiences and told my profile service to compile the audience. While the audience was compiling I applied it to my Personalized Link for Timesheet Review. I then checked to see that the audience had compiled and took a look at my My Site…no Timesheet Review link.

I took another look at my audience and realized it had 0 members, so I decided to delete it. After deleting the audience I then decided I would remove the Timesheet Review Link for the time being ad that is where the trouble began.

When I pulled up the Personalized Links page the only item showing where my links should have been was a message “The query returned and error. Contract your SharePoint Administrator” *Crap! I am the SharePoint Administrator! *

Ok, I figured I could fix this easily, I’ll just recreate the Audience with the same name…Nope, same error message.

Ok, the add new link button is available, I’ll add a new Link and the bad one will get “fixed” magically…Nope, no magic here.

Ok, so I checked my SharePoint Logs, my server application logs, and everywhere else in hopes I would see what the exact error was, alas nothing…

Fine, SharePoint is nothing more than a database application when we boil it down to the root I decided to crack it open and see what was going on. I opened the My Site Content Database and began looking at the various tables and opening the ones I thought had the highest probability of containing the list of links I had created.

After about an hour of searching I finally opened the table SharedListSync, and there I found my entry for the Timesheet Review along with the audience GUID. I decided the best method at this point was to change the audience GUID to 0, like the other entries that I had not applied Audiences to.

When I returned to the Personalized Links page sure enough all the links I had entered were now available and I was able to finally remove the Timesheet Review link.