I have been working on a CSR script for the New / Edit / Display forms of a list.
I am attempting to use OnPostRender to perform an action after all fields on the form have been rendered (hide a particular tr).
At the moment my testing is showing OnPostRender firing once per field and before the 3 'InitCallback' (one for each customized field) events fire.
Even with the simplest example I can find, OnPostRender seems to fire for each field.
function $_global_kgjslinkcontactsnew_test() {
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
OnPreRender: function () { console.log('CSR OnPreRender'); },
OnPostRender: function () { console.log('CSR OnPostRender'); }
});
} $_global_kgjslinkcontactsnew_test();
My full script is posted below but I think this must be behavior by design.
How do you apply CSR code once after the form is rendered ???
I have a function to return the default SharePoint HTML for my fields and another that I am using in the OnPostRender to hide a particular tr in the DOM but even with those commented out I am getting the same effect.
Is there an error in my script or is OnPostRender supposed to fire once per field ? If it is, how can I run my function once after all fields have rendered ?
function $_global_kgjslinkcontactsnew_test() {
Type.registerNamespace('KG');
KG.jslink_contactsnew = KG.jslink_contactsnew || {};
KG.jslink_contactsnew.Templates = KG.jslink_contactsnew.Templates || {};
KG.jslink_contactsnew.Functions = KG.jslink_contactsnew.Functions || {};
KG.jslink_contactsnew.Functions.test = function (ctx) {
var html = KG.jslink_contactsnew.Functions.getDefaultFieldHtml(ctx, ctx.CurrentFieldSchema, ctx.CurrentItem, ctx.ListSchema);
var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);
var fieldInternalName = ctx.CurrentFieldSchema.Name;
var contactTypeName = "KGContactType";
var contactTypeField = window[ctx.FormUniqueId + "FormCtx"].ListSchema[contactTypeName];
var contactTypeControlId = contactTypeField.Name + "_" + contactTypeField.Id + "_$DropDown" + contactTypeField.FieldType + "Field";
var contactTypeValue = window[ctx.FormUniqueId + "FormCtx"].ListData["KGContactType"];
//Register GetValueCallback function for current field for when save is clicked.
formCtx.registerGetValueCallback(formCtx.fieldName, function () {
return document.getElementById(formCtx.fieldSchema.Id).value;
});
//Register InitCallBack function for current field for when it changes.
formCtx.registerInitCallback(formCtx.fieldName, function () {
console.log("init function ran for " + formCtx.fieldName);
});
return html;
}
KG.jslink_contactsnew.Functions.testOnPostRender = function (ctx) {
console.log("OnPostRender");
var contactTypeName = "KGContactType";
var contactTypeField = window[ctx.FormUniqueId + "FormCtx"].ListSchema[contactTypeName];
var contactTypeControlId = contactTypeField.Name + "_" + contactTypeField.Id + "_$DropDown" + contactTypeField.FieldType + "Field";
var contactTypeValue = window[ctx.FormUniqueId + "FormCtx"].ListData["KGContactType"];
var firstNameName = "FirstName";
var firstNameField = window[ctx.FormUniqueId + "FormCtx"].ListSchema[firstNameName];
var firstNameControlId = firstNameField.Name + "_" + firstNameField.Id + "_$" + firstNameField.FieldType + "Field";
var firstNameControl = document.getElementById(firstNameControlId);
var el;
if (contactTypeValue == "Organization") {
el = KG.jslink_contactsnew.Functions.upTo(firstNameControl, "tr");
el.style.display = "";
}
else {
el = KG.jslink_contactsnew.Functions.upTo(firstNameControl, "tr");
el.style.display = "none";
}
// Find first ancestor of el with tagName
// or undefined if not found
}
KG.jslink_contactsnew.Functions.upTo = function (el, tagName) {
tagName = tagName.toLowerCase();
while (el && el.parentNode) {
el = el.parentNode;
if (el.tagName && el.tagName.toLowerCase() == tagName) {
console.log("found " + el.tagName);
return el;
}
else { console.log(el.tagName); }
}
// Many DOM methods return null if they don't
// find the element they are searching for
// It would be OK to omit the following and just
// return undefined
return null;
}
KG.jslink_contactsnew.Functions.getDefaultFieldHtml = function (renderCtx, field, listItem, listSchema) {
// Get field type and whether we are in DISPLAY , NEW, EDIT or VIEW mode.
var fieldType = renderCtx.CurrentFieldSchema.FieldType;
var controlMode = renderCtx.ControlMode;
// DISPLAY FORM default field rendering.
if (controlMode == 1) {
switch (renderCtx.CurrentFieldSchema.FieldType) {
case 'Text':
return SPField_FormDisplay_Default(renderCtx);
case 'Number':
return SPField_FormDisplay_Default(renderCtx);
case 'Integer':
return SPField_FormDisplay_Default(renderCtx);
case 'Boolean':
return SPField_FormDisplay_DefaultNoEncode(renderCtx);
case 'Note':
return SPFieldNote_Display(renderCtx);
case 'Currency':
return SPField_FormDisplay_Default(renderCtx);
case 'File':
return SPFieldFile_Display(renderCtx);
case 'Calculated':
return SPField_FormDisplay_Default(renderCtx);
case 'Choice':
return SPField_FormDisplay_Default(renderCtx);
case 'MultiChoice':
return SPField_FormDisplay_Default(renderCtx);
case 'Lookup':
return SPFieldLookup_Display(renderCtx);
case 'LookupMulti':
return SPFieldLookup_Display(renderCtx);
case 'Computed':
return SPField_FormDisplay_Default(renderCtx);
case 'URL':
return SPFieldUrl_Display(renderCtx);
case 'User':
return SPFieldUser_Display(renderCtx);
case 'UserMulti':
return SPFieldUserMulti_Display(renderCtx);
case 'DateTime':
return SPFieldDateTime_Display(renderCtx);
case 'Attachments':
return SPFieldAttachments_Display(renderCtx);
default:
console.log("Fieldtype " + fieldType + "not found");
return "";
}
}
// NEW and EDIT FORM default field rendering.
if (controlMode == 2 || controlMode == 3) {
switch (renderCtx.CurrentFieldSchema.FieldType) {
case 'Text':
return SPFieldText_Edit(renderCtx);
case 'Number':
return SPFieldNumber_Edit(renderCtx);
case 'Integer':
return SPFieldNumber_Edit(renderCtx);
case 'Boolean':
return SPFieldBoolean_Edit(renderCtx);
case 'Note':
return SPFieldNote_Edit(renderCtx);
case 'Currency':
return SPFieldNumber_Edit(renderCtx);
case 'File':
return SPFieldFile_Edit(renderCtx);
case 'Calculated':
return SPField_FormDisplay_Empty(renderCtx);
case 'Choice':
return SPFieldChoice_Edit(renderCtx);
case 'MultiChoice':
return SPFieldMultiChoice_Edit(renderCtx);
case 'Lookup':
return SPFieldLookup_Edit(renderCtx);
case 'LookupMulti':
return SPFieldLookup_Edit(renderCtx);
case 'Computed':
return SPField_FormDisplay_Default(renderCtx);
case 'URL':
return SPFieldUrl_Edit(renderCtx);
case 'User':
return SPClientPeoplePickerCSRTemplate(renderCtx);
case 'UserMulti':
return SPClientPeoplePickerCSRTemplate(renderCtx);
case 'DateTime':
return SPFieldDateTime_Edit(renderCtx);
case 'Attachments':
return SPFieldAttachments_Default(renderCtx);
default:
console.log("Fieldtype " + fieldType + "not found");
return "";
}
}
// VIEW default field rendering.
if (controlMode == 4) {
//Copy Paste of Jim Browns awesome helper function to return default View CSR field rendering
var renderingTemplateToUse = null;
var fieldRenderMap = {
Computed: new ComputedFieldRenderer(field.Name),
Attachments: new AttachmentFieldRenderer(field.Name),
User: new UserFieldRenderer(field.Name),
UserMulti: new UserFieldRenderer(field.Name),
URL: new UrlFieldRenderer(field.Name),
Note: new NoteFieldRenderer(field.Name),
Recurrence: new RecurrenceFieldRenderer(field.Name),
CrossProjectLink: new ProjectLinkFieldRenderer(field.Name),
AllDayEvent: new AllDayEventFieldRenderer(field.Name),
Number: new NumberFieldRenderer(field.Name),
BusinessData: new BusinessDataFieldRenderer(field.Name),
Currency: new NumberFieldRenderer(field.Name),
DateTime: new DateTimeFieldRenderer(field.Name),
Text: new TextFieldRenderer(field.Name),
Lookup: new LookupFieldRenderer(field.Name),
LookupMulti: new LookupFieldRenderer(field.Name),
WorkflowStatus: new RawFieldRenderer(field.Name)
};
if (field.XSLRender == '1') {
renderingTemplateToUse = new RawFieldRenderer(field.Name);
}
else {
renderingTemplateToUse = fieldRenderMap[field.FieldType];
if (renderingTemplateToUse == null)
renderingTemplateToUse = fieldRenderMap[field.Type];
}
if (renderingTemplateToUse == null)
renderingTemplateToUse = new FieldRenderer(field.Name);
return renderingTemplateToUse.RenderField(renderCtx, field, listItem, listSchema);
}
//No match found for default render.
console.log("CSR Default Field Render Failed...");
return "Default Field Render Failed";
}
KG.jslink_contactsnew.Templates.Fields = {
//'Title': {
// 'View': function () { return null; }
//},
'KGContactType': {
'EditForm': KG.jslink_contactsnew.Functions.test,
'NewForm': KG.jslink_contactsnew.Functions.test
},
'FullName': {
'EditForm': KG.jslink_contactsnew.Functions.test,
'NewForm': KG.jslink_contactsnew.Functions.test
},
'Company': {
'EditForm': KG.jslink_contactsnew.Functions.test,
'NewForm': KG.jslink_contactsnew.Functions.test
}
}
KG.jslink_contactsnew.Templates.OnPostRender = KG.jslink_contactsnew.Functions.testOnPostRender;
//KG.jslink_contactsnew.BaseViewID = 1;
KG.jslink_contactsnew.ListTemplateType = 105;
//Make the magic happen....
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(KG.jslink_contactsnew);
} $_global_kgjslinkcontactsnew_test();
OnPreRenderandOnPostRenderwill fire once per field (since that's the scope you set), but if you set the Target Control Type to "View", they will fire only once per entire view rendering. I have tested that with View, and I had it work as expected. I do not know the behavior is if you set the Target Control Type to "Form". – Dylan Cristy Apr 17 '15 at 21:40http://www.eliostruyf.com/display-template-custom-document-properties-explained/
The link above seems to suggest that the property defines which display templates can be used where, presumably when accessed from the MPG ?
I use code to set the jslink on my forms (http://sharepoint.stackexchange.com/questions/77976/set-the-jslink-property-for-all-list-forms-in-featureactivated).
– Satyrical Apr 17 '15 at 22:36