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();
OnPreRender
andOnPostRender
will 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".