JSLink files have the ability to quickly and easily change how list views and forms are rendered. More specifically: how the fields in that list should be displayed.
JSLink, on the other hand, is a property available on many SharePoint objects, including Fields, Lists, Views, and Content Types. In its simplest form, the JSLink property simply adds a JavaScript file to the page. Depending on the JavaScript, this could then do anything – either related to the object to which it was attached, or something completely unrelated, if desired.
How JSLink works:
SharePoint rendering systems (XSLT in 2010 and CAML in 2007), CSR is client-side. The only thing server-side web parts do is put a huge amount of raw data into the page, in JSON format. This data become a JS object when the page loads, and from then on the Client Side Rendering begins.
So basically, what CSR does is take the JS object with raw data as input, then renders a huge HTML string based on it:
After the HTML string is fully formed, it is inserted into the DOM.
Client Site Rendering processing of the raw data is divided into stages, each represented by one overrideable JS function. Each function returns its own chunk of HTML. Stages are often nested into each other.
The stages order isn’t documented, so head first into the clienttemplates.debug.js file to figure it out. For list views, the order turns out to be the following:
Group, Item, and Field functions can be called many times, while View, Header, Body, and Footer are called only once.
Challenge
How do I create a custom List, custom List View, as well as content related to a custom display field and forms, lookup fields as cascading Drop-Downs (single-select) or checkboxes (multi-select) in SharePoint and Office 365, using the Visual Studio 2012 project template?
Solution
1. Custom client-side rendered view of a custom list
To create a project template, follow these steps:
- Open Visual Studio 2012, click New on the File menu, and then click Project.
- In the Templates pane, select the Office/SharePoint/Apps project template under SharePoint 2012 templates folder.
- In the Name box, provide a name for your solution.
In the Name box, input CustomListView and then click OK:
At this point, the SharePoint Customization Wizard will appear:
- You will see a SharePoint Customization Wizard asking for a local site for debugging and deployment. Enter the URL for the SharePoint server site where you want to debug the site definition or use the default location (http://system name/).
- Select SharePoint-hosted for”How do you want to host your app for SharePoint?”
- Click Finish. The project appears in Solution Explorer.
A new solution will be created as shown in the image below. Pages, Scripts, Features, and Package folders are created, too:
Step1: Create a custom list
Create a list by adding a new item to the project.
Enter the name of the SharePoint® list that you want to create and click on Add. It will open the wizard to choose the list settings:
Use the default (Blank) template to create the list and click finish:
Then choose Finish.
- The wizard creates a CustomList list template with a child list instance named CustomListInstance. A list designer may open. It is used in a later step.
- Expand the CustomListInstance node in Solution Explorer, if it isn’t already so that you can clearly distinguish the elements.xml file that is a child of the list instance from the elements.xml file that is a child of the list template.
Lists node in Solution Explorer:
- Open the elements.xml child of the CustomList list template.
- Add spaces to the DisplayName attribute (not the Name attribute) to make it friendlier: “CustomList”.
- Set the Description attribute to ” My List Definition.”
- Leave all other attributes at their default, save the file and close it.
- If the list designer is not open, choose the CustomList node in Solution Explorer.
- Open the List tab of the designer. This tab is used to set certain values for the list instance, not the list template, but it has some default values that it inherited from the template.
- Change the values on this tab to the following:
o Title: CustomList
o List URL: Lists/CustomList
o Description: My List Instance.
Leave the check boxes at their default status, save the file, and close the designer
Open the schema.xml file and create a custom view with
- Save and close the schema.xml file.
- Open the elements.xml file that is a child of the list instance CustomListInstance (not the elements.xml that is a child of the list template CustomList).
- In this file, populate the list with some initial data. You do this by adding the following Data element markup as a child element of the ListInstance element:
- Save and close the file.
To add a JavaScript file for the rendering logic of the custom view
- Right-click the Scripts folder in the solution project, and add a new JavaScript file.
- Name the JavaScript file CSRListView.js, which contains the rendering logic:
You can provide custom logic to control the rendering process of different template sets, such as the header, footer, or individual items in the list and code.
You can see more details about the format of the CSRListView.js file
-After that open the schema.xml file again at BaseViewID=”2″, under the <JSLink> element we need to replace “clienttemplates.js” by “~site/Scripts/CSRListView.js” and then Save and close the file.
Run and test the sample
o Press F5 to run and deploy the project.
o Provide a title for the list in the dialog box
You can see that the data has been added to the list instance and displayed in the custom view as shown in the following:
2. Custom client-side rendered form view: New, Edit, Display Form, and Lookup Field.
This sample demonstrates how to make some fields dependent from each other in SharePoint list item New and Edit forms. So e.g. if you change a value in one field, another field changes its appearance or number of variants, etc.
Do the same as section 1 (Custom client-side rendered view of a custom list) create new project with name is Scenario.JSLink as shown in the following:
-Next step, create folder Lists and add new two custom lists in the order named are Color and Trademark
-Open the elements.xml file that is a child of the list instance ColorInstance and populate the list with some initial data:
+ColorInstance :
+ TrademarkInstance:
– At Lists folder continue create custom list with name is LookupField:
At Schema.xml file, Be sure you have found the matching begin and end tags for the <Fields> element. Add line breaks to improve readability:
– Next step, right click Scenario.JSLink project and Add new item/Module with name is “Style Library”:
–At “Style Library” create a new folder with the name “LookupField” and add new lookup.js file:
– Copy the following code and paste it into the JavaScript file. The code performs the following tasks:
o Get the lookup value from Trademark and Color list and render the control drop-down list and a checkbox for a single value and multiple values.
o Creates a template for the field when it is displayed in a view, display, or edit form.
// create namespaces for our Display Templates
var jslinkTemplates = window.jslinkTemplates || {};
jslinkTemplates.Lookups = {};
jslinkTemplates.Lookups.Normal = {};
jslinkTemplates.Lookups.Normal.SingleItem = {};
jslinkTemplates.Lookups.Normal.MultiItem = {};
jslinkTemplates.Lookups.registerCallBack = function (ctx) {
var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);
// registers the callback for the specified field
if (ctx.CurrentFieldSchema.Type == “Lookup” &&
ctx.CurrentFieldSchema.FieldType == “Lookup”) {
formCtx.registerGetValueCallback(formCtx.fieldName,
jslinkTemplates.Lookups.getSingleValue.bind(null, formCtx.fieldName));
}
else if
(ctx.CurrentFieldSchema.Type == “Lookup” &&
ctx.CurrentFieldSchema.FieldType == “LookupMulti”) {
formCtx.registerGetValueCallback(formCtx.fieldName,
jslinkTemplates.Lookups.getMultiValue.bind(null, formCtx.fieldName));
}
};
jslinkTemplates.Lookups.getMultiValue = function (fieldName) {
// returns the value of our
multi-lookup field
//debugger;
var returnValue = ”;
// get the values we want
var checkboxes =
$(“#” + fieldName + “LookupValues input[type=checkbox]:checked”);
//var checkboxes =
$(“input[type=checkbox]:checked”);
for (var i = 0; i <
checkboxes.length; i++) {
if (returnValue != ”) {
returnValue += ‘;#’
}
returnValue +=
checkboxes.value;
}
return returnValue;
};
jslinkTemplates.Lookups.getSingleValue = function (fieldName, textOnly) {
// returns the value of our
single-item lookup field
// option to just return the
text value
//debugger;
var selectedValue =
$(“#” + fieldName + “LookupValues option:selected”);
if (selectedValue[0]) {
if (textOnly) {
return selectedValue[0].innerText;
}
else {
return
selectedValue[0].value;
}
}
else {
return null;
}
};
jslinkTemplates.Lookups.Normal.SingleItem.editForm = function
(formContext) {
//debugger;
var queryStringId =
jslinkTemplates.Lookups.getQuerystring(formContext.CurrentFieldSchema.Name);
// we need this if we use the
looking as a cascading drop-down anywhere
jslinkTemplates.Lookups.registerCallBack(formContext);
var returnHtml = “<div
id='” + formContext.CurrentFieldSchema.Name +
“LookupValues’>”;
returnHtml +=
“<select”;
if (queryStringId !=
“”) {
returnHtml += “
disabled=’true’ title=’You cannot change this field'”;
}
returnHtml += “>”;
if
(!formContext.CurrentFieldSchema.Required) {
returnHtml +=
“<option value=””;
if
(formContext.CurrentFieldValue == “”) {
returnHtml += “
selected=’true'”;
}
returnHtml +=
“>(None)</option>”;
}
var choices =
formContext.CurrentFieldSchema.Choices;
for (var i = 0; i <
choices.length; i++) {
var lookupString =
choices.LookupId + “;#” + choices.LookupValue;
returnHtml +=
“<option value='” + lookupString + “‘”;
if (choices.LookupId ==
queryStringId) {
returnHtml += “
selected=’true'”;
}
else if
(formContext.CurrentFieldValue == lookupString) {
returnHtml += “
selected=’true'”;
}
returnHtml +=
“>” + choices.LookupValue + “</option>”;
}
returnHtml +=
“</select></div>”;
return returnHtml;
}
jslinkTemplates.Lookups.Normal.MultiItem = function (formContext) {
//debugger;
jslinkTemplates.Lookups.registerCallBack(formContext);
//var formCtx =
SPClientTemplates.Utility.GetFormContextForCurrentField(formContext);
var choices =
formContext.CurrentFieldSchema.Choices;
var returnHtml = “<div
id='” + formContext.CurrentFieldSchema.Name +
“LookupValues’>”;
for (var i = 0; i <
choices.length; i++) {
var choiceText =
choices.LookupValue;
var choiceValue =
choices.LookupId + ‘;#’ + choices.LookupValue;
returnHtml +=
“<input type=’checkbox’ name='” + choiceText + “‘
value='” + choiceValue + “‘ style=’float: left;'”;
if
(formContext.CurrentFieldValue &&
formContext.CurrentFieldValue.indexOf(choiceValue) != -1) {
// if the item contains
the current checkbox value then check it
returnHtml += “
checked “;
}
returnHtml +=
“/><span style=’display: block; padding-left: 25px; min-height:
20px;’>” + choiceText + “</span>”;
}
returnHtml +=
“</div>”;
return returnHtml;
}
jslinkTemplates.Lookups.Normal.view = function (viewContext) {
var values =
viewContext.CurrentItem[viewContext.CurrentFieldSchema.Name];
if (values.length > 1) {
var returnHtml =
“<ul style=’margin-top: 0px; margin-bottom: 0px;’>”;
for (var i = 0; i <
values.length; i++) {
// add a new LI element
for each value
returnHtml +=
“<li>” + values.lookupValue + “</li>”;
}
returnHtml +=
“</ul>”;
return returnHtml;
}
else if (values.length == 1) {
return
“<span>” + values[0].lookupValue + “</span>”;
}
else {
return “”;
}
};
jslinkTemplates.Lookups.Normal.displayForm = function (formContext) {
//debugger;
if (formContext.CurrentFieldValue
!= “”) {
var returnHtml =
“<ul style=’margin-top: 0px; margin-bottom: 0px;’>”;
var values =
formContext.CurrentItem[formContext.CurrentFieldSchema.Name].toString();
if (values.length > 1) {
var choices = formContext.CurrentFieldSchema.Choices;
for (var i = 0; i <
choices.length; i++) {
if
(values.indexOf(choices.LookupValue) != -1) {
returnHtml +=
“<li>” + choices.LookupValue + “</li>”;
}
}
returnHtml +=
“</ul>”;
return returnHtml;
}
}
else {
return “”;
}
};
jslinkTemplates.Lookups.getQuerystring = function (key, defaultValue) {
if (defaultValue == null)
defaultValue = “”;
key = key.replace(/[[]/,
“[“).replace(/[]]/, “]”);
var regex = new
RegExp(“[?&]” + key + “=([^&#]*)”);
var qs =
regex.exec(window.location.href);
if (qs == null)
return defaultValue;
else
return qs[1];
};
– Save and close the file.
– Next, create a new folder named “TemplateOverrides” in the “Style Library” folder and add LookUpOverrides.js file:
– And then copy the following code and paste it into the JavaScript file. The code performs the following tasks:
o Creates a template for the field when it is displayed in a view form, new form, edit form, display form
o Registers the template.
o Provides the rendering logic for the field type when used displayed in a view form, new form, edit form, display form.
– Save and close the file.
Run and test the sample
o Press F5 to run and deploy the project.
You can see that the data has been added to the list instance and displayed as shown:
+ Screenshot below indicates for new item:
+ View form:
+ Display Form:
+ Edit form:
3. This is a simple color picker scenario with all of the HTML colors rendering in a drop-down list, with the actual color being shown in the View and Display Form.
– Do the same in sections 1 and 2: In Lists folder create custom list with name ColorPicker:
At Schema.xml file, be sure you have found the matching begin and end tags for the <Fields> element. Add line breaks to improve readability:
– And the following code in the JavaScript file to render the drop-down list gets colors:
var jslinkTemplates = window.jslinkTemplates || {};
jslinkTemplates.Colours =
function () {
var selectIdPrefix = “COL_”;
var errorIdPrefix = “ERR_”;
var display = function (ctx) {
// return our string
return getColourSpan(ctx.CurrentItem[“Colour”]);
};
var edit = function (ctx) {
// create form context object
var formCtx =
SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);
// register our custom validator
var validator = new
SPClientForms.ClientValidation.ValidatorSet();
validator.RegisterValidator(new
jslinkTemplates.Colours.validator());
formCtx.registerClientValidator(formCtx.fieldName, validator);
// register our callbacks
formCtx.registerGetValueCallback(formCtx.fieldName,
jslinkTemplates.Colours.getValue.bind(null, formCtx.fieldName));
formCtx.registerValidationErrorCallback(formCtx.fieldName,
jslinkTemplates.Colours.onError.bind(null, formCtx.fieldName));
var returnHtml = “”;
//#region array of available colours
var colours = new
Array(“AliceBlue”,
“AntiqueWhite”,
“Aqua”,
“Aquamarine”,
“Azure”,
“Beige”,
“Bisque”,
“Black”,
“Turquoise”,
“Violet”,
“Wheat”,
“White”,
“WhiteSmoke”,
“Yellow”,
“YellowGreen”);
//#endregion
returnHtml += “<select
id='” + selectIdPrefix + formCtx.fieldName + “‘>”;
for (var i = 0; i < colours.length;
i++) {
// create a drop-down option
returnHtml += “<option
value='” + colours+ “‘”;
if (ctx.CurrentItem[“Colour”]
== colours{
// make sure the current field
value is selected
returnHtml += “
selected=’true’ “;
}
returnHtml += “>” +
getColourSpan(colours) + “</option>”;
}
returnHtml +=
“</select>”;
// add an error span for our validator
to use
returnHtml += “<br/><span
id='” + errorIdPrefix + formCtx.fieldName + “‘
class=’ms-formvalidation
ms-csrformvalidation’></span><br/>”;
return returnHtml;
};
var getColourSpan = function (colour) {
var returnHtml = “”;
returnHtml += “<div
style=’background: ” + colour + “; width: 20px; float:
left’> </div>”;
returnHtml += “<div
style=’margin-left: 30px;’>” + colour + “</div>”;
return returnHtml;
};
var getValue = function (fieldName) {
var selector = ‘#’ + selectIdPrefix +
fieldName;
return $(selector).val();
};
var validator = function () {
jslinkTemplates.Colours.validator.prototype.Validate
= function (value) {
var isError = false;
var errorMessage = “”;
if (value == “Blue”) {
isError = true;
errorMessage = “Sorry, we
don’t like the colour blue”;
}
return new
SPClientForms.ClientValidation.ValidationResult(isError, errorMessage);
};
};
var onError = function (fieldName, error) {
var selector = ‘#’ + errorIdPrefix +
fieldName;
$(selector).html(“<span role=’alert’>”
+ error.errorMessage + “</span>”);
};
return {
“display”: display,
“edit”: edit,
“getValue”: getValue,
“validator”: validator,
“onError”: onError
}
}();
-Save and close the file.
– Next, create new folder name is “TemplateOverrides” in “Style Library” folder and add FavouriteColours.js file as follows:
– And then copy the following code and paste it in the JavaScript file. The code performs the following tasks:
o Creates a template for the field when it is displayed.
o Registers the template.
o Provides the rendering logic for the field type and this also includes an example of a “Validator” where you can control validation of data entry through the SharePoint Client Site Rendering techniques.
Run and test the sample
o Press F5 to run and deploy the project.
You can see that the data has been added to the list instance and display as shown in the following figure
+ New item:
+
Display Form:
+ View Form:
Our final solution structure should now look like the following figure:
All done! Our solution is now ready to publish into a .app file and deployment into the SharePoint app and Office 365.
You can download a demo project here.
I hope you found it helpful to learn how to create a more full-featured JsLink, incorporating several features and elements you may wish to add.