SharePoint 2013 - Client Side Rendering
1. Client side rendering 代码结构为:
(function () { // Create object that have the context information about the field that we want to change it's output render var linkFilenameFiledContext = {}; linkFilenameFiledContext.Templates = {}; linkFilenameFiledContext.Templates.Fields = { // Apply the new rendering for LinkFilename field on list view "LinkFilename": { "View": linkFilenameFiledTemplate } }; SPClientTemplates.TemplateManager.RegisterTemplateOverrides(linkFilenameFiledContext); })();
2. Client Side Rendering 可以用来注册一个对象,这个对象用于去进行模板覆盖,对象包含以下几种属性:
View
Header
Body
Footer
Group
Item
Fields
OnPreRender
OnPostRende
3. Fields属性的格式为:overrideCtx.Templates.Fields = {FieldName : {Scope : Override}}, 使用ctx.CurrentFieldSchema.Name 来获取field的内部名称,例如:var priorityValue = ctx.CurrentItem[ctx.CurrentFieldSchema.Name]
FieldName - This is the internal name of the field you want to override. Scope – This defines when to override the field. The choices are “View”,”DisplayForm”,”EditForm”, and “NewForm”. Override – The actual override. This can be a HTML string with JavaScript embedded, or a function to be executed. In the former, it should be in the format: “<p> <#= ctx.CurrentItem.PercentComplete #></p>”, where “<p>” is just some HTML, and everything enclosed in “<#= #>” is JavaScript to be executed.
4. 使用clientform.js, clientpeoplepicker.js, 和autofill.js文件来生成client people picker:
页面代码:
<SharePoint:ScriptLink name="clientforms.js" runat="server" LoadAfterUI="true" Localizable="false" /> <SharePoint:ScriptLink name="clientpeoplepicker.js" runat="server" LoadAfterUI="true" Localizable="false" /> <SharePoint:ScriptLink name="autofill.js" runat="server" LoadAfterUI="true" Localizable="false" /> <div id="peoplePickerDiv"></div>
JS代码:
function initializePeoplePicker(peoplePickerElementId) { // Create a schema to store picker properties, and set the properties. var schema = {}; schema['PrincipalAccountType'] = 'User,DL,SecGroup,SPGroup'; schema['SearchPrincipalSource'] = 15; schema['ResolvePrincipalSource'] = 15; schema['AllowMultipleValues'] = true; schema['MaximumEntitySuggestions'] = 50; schema['Width'] = '280px'; // Render and initialize the picker. // Pass the ID of the DOM element that contains the picker, an array of initial // PickerEntity objects to set the picker value, and a schema that defines // picker properties. this.SPClientPeoplePicker_InitStandaloneControlWrapper(peoplePickerElementId, null, schema);
5. 修改View或者Field的显示方式时,需要使用clienttemplate.js文件,参考示例;
具体操作为:先创建一个对象来存储要更改对象的上下文信息,然后使用SPClientTemplates.TemplateManager.RegisterTemplateOverrides()来注册这个对象进行覆盖;
修改View显示方式的JS代码:
(function () { // Initialize the variable that store the objects. var overrideCtx = {}; overrideCtx.Templates = {}; // Assign functions or plain html strings to the templateset objects: // header, footer and item. overrideCtx.Templates.Header = "<B><#=ctx.ListTitle#></B>" + "<hr><ul id='unorderedlist'>"; // This template is assigned to the CustomItem function. overrideCtx.Templates.Item = customItem; overrideCtx.Templates.Footer = "</ul>"; // Set the template to the: // Custom list definition ID // Base view ID overrideCtx.BaseViewID = 2; overrideCtx.ListTemplateType = 10057; // Assign a function to handle the // PreRender and PostRender events overrideCtx.OnPreRender = preRenderHandler; overrideCtx.OnPostRender = postRenderHandler; // Register the template overrides. SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx); })(); // This function builds the output for the item template, // it uses the context object to access announcement data. function customItem(ctx) { // Build a listitem entry for every announcement in the list. var ret = "<li>" + ctx.CurrentItem.Title + "</li>"; return ret; } // The preRenderHandler handles the // OnPreRender event function preRenderHandler(ctx) { // Override the default title with user input ctx.ListTitle = prompt("Type a title", ctx.ListTitle); } // The postRenderHandler handles the // OnPostRender event function postRenderHandler(ctx) { // You can manipulate the DOM // in the postRender event var ulObj; var i, j; ulObj = document.getElementById("unorderedlist"); // Reverse order the list for (i = 1; i < ulObj.children.length; i++) { var x = ulObj.children[i]; for (j = 1; j < ulObj.children.length; j++) { var y = ulObj.children[j]; if(x.innerText<y.innerText){ ulObj.insertBefore(y, x); } } } }
修改Field显示方式的JS代码(可以为Field提供View, DisplayForm, EditForm, NewForm的显示模板):
// List View – Priority Color Sample // Muawiyah Shannak , @MuShannak (function () { // Create object that have the context information about the field that we want to change it's output render var priorityFiledContext = {}; priorityFiledContext.Templates = {}; priorityFiledContext.Templates.Fields = { // Apply the new rendering for Priority field on List View "Priority": { "View": priorityFiledTemplate } }; SPClientTemplates.TemplateManager.RegisterTemplateOverrides(priorityFiledContext); })(); // This function provides the rendering logic for list view function priorityFiledTemplate(ctx) { var priority = ctx.CurrentItem[ctx.CurrentFieldSchema.Name]; // Return html element with appropriate color based on priority value switch (priority) { case "(1) High": return "<span style='color :#f00'>" + priority + "</span>"; break; case "(2) Normal": return "<span style='color :#ff6a00'>" + priority + "</span>"; break; case "(3) Low": return "<span style='color :#cab023'>" + priority + "</span>"; } }
为Field提交时注册事件的JS代码:
(function () { // Create object that have the context information about the field that we want to change it's output render var ageFiledContext = {}; ageFiledContext.Templates = {}; ageFiledContext.Templates.Fields = { // Apply the new rendering for Age field on New and Edit forms "Age": { "NewForm": ageFiledTemplate, "EditForm": ageFiledTemplate } }; SPClientTemplates.TemplateManager.RegisterTemplateOverrides(ageFiledContext); })(); // This function provides the rendering logic function ageFiledTemplate(ctx) { var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctx); // Register a callback just before submit. formCtx.registerGetValueCallback(formCtx.fieldName, function () { return document.getElementById('inpAge').value; }); // Render Html5 input (number) return "<input type='number' id='inpAge' min='0' max='110' value='" + formCtx.fieldValue + "'/>"; }
6. 在除浏览器地址栏之外的其它地方,尽量不要使用%20替代空格,否则,在非IE浏览器(例如Chrome)中不能够识别,比如:
此处如果使用%20,则在Chrome中不能工作;
而且不能使用绝对路径或者相对路径,要使用token符号来替代web路径,详情参考此页面;
JSLink URLs and Tokens
When you are constructing your JSLink URL there are a number of tokens you can take advantage of:
~site – reference to the current SharePoint site (or “Web”)
~sitecollection – reference to the current SharePoint site collection (or “Site”)
~layouts – version specific reference to the web application Layouts folder (so it will automatically swap out /_layouts/14 or /_layouts/15 for you)
~sitecollectionlayouts – reference to the layouts folder in the current site collection (e.g. /sites/team/_layouts/15)
~sitelayouts – reference to the layouts folder in the current site (e.g. /sites/teams/subsite/_layouts/15)
7. 为Field添加验证时需要用到 SPClientForms.ClientValidation 对象
var validators = new SPClientForms.ClientValidation.ValidatorSet(); validators.RegisterValidator(new emailValidator()); // Validation failure handler. formCtx.registerValidationErrorCallback(formCtx.fieldName, emailOnError); formCtx.registerClientValidator(formCtx.fieldName, validators); // Custom validation object to validate email format emailValidator = function () { emailValidator.prototype.Validate = function (value) { var isError = false; var errorMessage = ""; //Email format Regex expression var emailRejex = /\S+@\S+\.\S+/; if (!emailRejex.test(value) && value.trim()) { isError = true; errorMessage = "Invalid email address"; } //Send error message to error callback function (emailOnError) return new SPClientForms.ClientValidation.ValidationResult(isError, errorMessage); }; }; // Add error message to spnError element under the input field element function emailOnError(error) { document.getElementById("spnError").innerHTML = "<span role='alert'>" + error.errorMessage + "</span>"; }
8. 设置Field为只读时,可以使用SharePoint已有的javascript方法:
// List add and edit – ReadOnly SP Controls Sample (function () { // Create object that have the context information about the field that we want to change it's output render var readonlyFiledContext = {}; readonlyFiledContext.Templates = {}; readonlyFiledContext.Templates.Fields = { // Apply the new rendering for Age field on Edit forms "Title": { "EditForm": readonlyFieldTemplate } }; SPClientTemplates.TemplateManager.RegisterTemplateOverrides(readonlyFiledContext); })(); // This function provides the rendering logic function readonlyFieldTemplate(ctx) { //Reuse ready sharepoint javascript libraries switch (ctx.CurrentFieldSchema.FieldType) { case "Text": case "Number": case "Integer": case "Currency": case "Choice": case "Computed": return SPField_FormDisplay_Default(ctx); case "MultiChoice": prepareMultiChoiceFieldValue(ctx); return SPField_FormDisplay_Default(ctx); case "Boolean": return SPField_FormDisplay_DefaultNoEncode(ctx); case "Note": prepareNoteFieldValue(ctx); return SPFieldNote_Display(ctx); case "File": return SPFieldFile_Display(ctx); case "Lookup": case "LookupMulti": return SPFieldLookup_Display(ctx); case "URL": return RenderFieldValueDefault(ctx); case "User": prepareUserFieldValue(ctx); return SPFieldUser_Display(ctx); case "UserMulti": prepareUserFieldValue(ctx); return SPFieldUserMulti_Display(ctx); case "DateTime": return SPFieldDateTime_Display(ctx); case "Attachments": return SPFieldAttachments_Default(ctx); case "TaxonomyFieldType": //Re-use ready sharepoint inside sp.ui.taxonomy.js javascript libraries return SP.UI.Taxonomy.TaxonomyFieldTemplate.renderDisplayControl(ctx); } } //User control need specific formatted value to render content correctly function prepareUserFieldValue(ctx) { var item = ctx['CurrentItem']; var userField = item[ctx.CurrentFieldSchema.Name]; var fieldValue = ""; for (var i = 0; i < userField.length; i++) { fieldValue += userField[i].EntityData.SPUserID + SPClientTemplates.Utility.UserLookupDelimitString + userField[i].DisplayText; if ((i + 1) != userField.length) { fieldValue += SPClientTemplates.Utility.UserLookupDelimitString } } ctx["CurrentFieldValue"] = fieldValue; } //Choice control need specific formatted value to render content correctly function prepareMultiChoiceFieldValue(ctx) { if (ctx["CurrentFieldValue"]) { var fieldValue = ctx["CurrentFieldValue"]; var find = ';#'; var regExpObj = new RegExp(find, 'g'); fieldValue = fieldValue.replace(regExpObj, '; '); fieldValue = fieldValue.replace(/^; /g, ''); fieldValue = fieldValue.replace(/; $/g, ''); ctx["CurrentFieldValue"] = fieldValue; } } //Note control need specific formatted value to render content correctly function prepareNoteFieldValue(ctx) { if (ctx["CurrentFieldValue"]) { var fieldValue = ctx["CurrentFieldValue"]; fieldValue = "<div>" + fieldValue.replace(/\n/g, '<br />'); + "</div>"; ctx["CurrentFieldValue"] = fieldValue; } }
8. 隐藏Field时,可以在OnPostRender事件中使用jQuery方法:
(function () { // jQuery library is required in this sample // Fallback to loading jQuery from a CDN path if the local is unavailable (window.jQuery || document.write('<script src="//ajax.aspnetcdn.com/ajax/jquery/jquery-1.10.0.min.js"><\/script>')); // Create object that have the context information about the field that we want to change it's output render var hiddenFiledContext = {}; hiddenFiledContext.Templates = {}; hiddenFiledContext.Templates.OnPostRender = hiddenFiledOnPreRender; hiddenFiledContext.Templates.Fields = { // Apply the new rendering for Age field on New and Edit forms "Predecessors": { "NewForm": hiddenFiledTemplate, "EditForm": hiddenFiledTemplate } }; SPClientTemplates.TemplateManager.RegisterTemplateOverrides(hiddenFiledContext); })(); // This function provides the rendering logic function hiddenFiledTemplate() { return "<span class='csrHiddenField'></span>"; } // This function provides the rendering logic function hiddenFiledOnPreRender(ctx) { jQuery(".csrHiddenField").closest("tr").hide(); }
9. 使用sp.ui.controls.js文件来定义client chrome control,需要使用jQuery或MicrosoftAjax.js来支持:
// Prepare the options and render the control // The Help, Account and Contact pages receive the // same query string parameters as the main page var options = { "appIconUrl": "../Images/AppIcon.png", "appTitle": "Basic tasks using the JSOM", "appHelpPageUrl": "Help.html?" + document.URL.split("?")[1], "settingsLinks": [ { "linkUrl": "Account.html?" + document.URL.split("?")[1], "displayName": "Account settings" }, { "linkUrl": "Contact.html?" + document.URL.split("?")[1], "displayName": "Contact us" } ] }; var nav = new SP.UI.Controls.Navigation( "chrome_ctrl_placeholder", options ); nav.setVisible(true);
效果为:
10. mapviewtemplate.js用来设置一个含有geolocation类型字段的视图,效果如下:
11.