SharePoint 2013 AverageRatingFieldControl JavaScript Error and No Images

26/07/2014

The 5-star rating feature for list and libraries was introduced in SharePoint 2010 and by using the AverageRatingFieldControl is was easy to enable users to rate and see the current rating on custom page layouts. Unfortunately this corner of SharePoint has been overlooked in SharePoint 2013, so now the AverageRatingFieldControl have a few bugs that if not handled leaves it broken after your site is upgrade to SharePoint 2013.

Update 16/01/2015: I have been informed that there’s a bug in my C# fix, because sometimes the avgRating value is actually > 9,XXXX I have seen a case where it was 1234,56. I changed the code to handle this type of rating values. I also checked if the bug is fixed in a recent CU (November 2014), and it is. So if you are SharePoint is November 2014 CU or newer you don’t need the C# fix anymore, I haven’t verified if the Star Images bugs are fixed too.

No Star Images Showing on Custom Page Layouts

If you have the AverageRatingFieldControl added to a custom page layout in SharePoint 2013 visited by Internet Explorer 10 or newer, you will notice that the images are not loaded after the initial page load, but they do show up after a page refresh.
averageratingfieldcontrolerror
The reason for this odd behavior, is problems with the JavaScript execution order, that have changed slightly from SharePoint 2010 to SharePoint 2013. Really a fix should be supplied by Microsoft, but until that happens we have to do something ourselves. What we need to do is to re-execute the JavaScript responsible for setting up the star images and the rating control, when everything on the page have been properly loaded. The easiest way to do so is adding the following JavaScript to our page layout, it requires JQuery to be loaded.
[js]
function fixIE10StarRatingIssue()
{
if (SP.UI.Reputation != null) {
SP.UI.Reputation.RatingsHelpers.$c(false);
jQuery(‘.pagerating > script’).each(function () {
eval($(this).text());
});
}
}
_spBodyOnLoadFunctionNames.push(‘fixIE10StarRatingIssue’);
[/js]
You have to change the code code>jQuery(‘.pagerating > script’) to match your markup so that is properly selects the JavaScript emitted by the AverageRatingFieldControl, here is how my markup looks.
[csharp]
<div class="pagerating">
<span class="padtop">Rating:&nbsp;</span><SharePointPortalControls:AverageRatingFieldControl
ID="PageRatingControl"
FieldName="AverageRating"
runat="server"/>
</div>
[/csharp]

JavaScript Error in Rating Field Control JavaScript when using None English Locals

Another error introduced by a change in SharePoint 2013, is that the rating control now emits JavaScript with errors if you use a localization that uses “,” as the decimal separator. This error is only visible if the average rating is a decimal number, so you might not notice it at first. But once the rating calculates to a decimal number the control will fail to work and your page will have a JavaScript error.

The way I choose to fix this was to inherit from the AverageRatingFieldControl and replace the erroneous part of the javascript, with something that works regardless of your localization settings. Here’s how my inherited AverageRatingFieldControl looks.
[csharp]
using Microsoft.SharePoint.Portal.WebControls;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web.UI;

namespace SharePoint.WebControls
{
public class ExtAverageRatingFieldControl : AverageRatingFieldControl
{
public override void RenderControl(System.Web.UI.HtmlTextWriter output)
{
StringBuilder sb = new StringBuilder();
base.RenderControl(new HtmlTextWriter(new StringWriter(sb)));

//Fix error in javascript outputtet by AverageRatingFieldControl
// it outputs javascript with comma as decimal seperator if current local uses that.
var r = new Regex(@"avgRating = (\d)*\,(\d)*;", RegexOptions.Multiline);
var outputText = sb.ToString();
var match = r.Match(outputText);
if (match.Success)
{
//Replace it
outputText = outputText.Replace(match.Value, match.Value.Replace(",", "."));
}
output.Write(outputText);

}
}
}
[/csharp]
This controls renders everything as normal to a stringbuilder, if the outputted html contains the erroneous javascript with a “,” as decimal separator we replace the “,” with a “.” and then output that to the response, if the JavaScript is good we just output it directly.