Tag: CSR

SharePoint column dependencies with Client-Side-Rendering (CSR)

Of course it is simple to inject a SharePoint list form with JavaScript and use some jQuery to add EventListeners and manipulate column behavior.

But to get more robust solutions and avoid direct DOM dependencies as much as possible I like the approach of Client-Side-Rendering (CSR). There are some good examples out there in the internet Link MSDN and Another Link, also not to neglect the great series from Martin Hatch, but today I want to show you how to make two columns work together.

Assume you have a simple Yes/No column and on click you want to show another column (Yes) or hide (No).

First we need our Template overrides (Line 1-12, see bottom):


CUSTOMER.SP.Title.fieldOverrides.Templates = CUSTOMER.SP.Title.fieldOverrides.Templates || {};
{
CUSTOMER.SP.Title.fieldOverrides.Templates.Fields =
{
'TitleOptPM': {
'EditForm': CUSTOMER.SP.Title.fieldOverrides.setOptPMChecked
},
'ProPlanTemplate': {
'EditForm': CUSTOMER.SP.Title.fieldOverrides.getPMTemplateRender
}
};
}

The first column is our Yes/No checkbox and the function is responsible for adding the event receiver.

The second is our dependent column and the referenced method is only to preserve some information about the rendered HTML to later find it.

Let’s start with the first function (Line 14-29, see bottom):


CUSTOMER.SP.Title.fieldOverrides.setOptPMChecked = function (ctx) {
var defaultHTML = SPFieldBoolean_Edit(ctx);
defaultHTML = defaultHTML.replace('<input', '<input onchange="CUSTOMER.SP.Title.fieldOverrides.optPMChanged(this)"');

var currentValue = ctx.CurrentItem[ctx.CurrentFieldSchema.Name];
// Hide select with original event receiver but dummy unchecked checkbox
if (currentValue == '0') {
var dummyChkBox = document.createElement('input');
dummyChkBox.type = 'checkbox';
dummyChkBox.checked = false;
$('document').ready(function () {
CUSTOMER.SP.Title.fieldOverrides.optPMChanged(dummyChkBox);
});
}
return defaultHTML;
};

The first two lines are sufficient at a first look. We create the defaultHTML. This means how SharePoint would render it without our “override”. SPFieldBoolean_Edit is the choice for a Boolean column in edit mode. Refer to Stackexchange for further standard render methods.

In the second line with a simple .replace() we inject our event receiver for onchange. In the end we return our defaultHTML.

But what about the rest in between? This is our “going in position”.

With var currentValue = ctx.CurrentItem[ctx.CurrentFieldSchema.Name]; we get the current value of the current field. Note this line of code works independently of the field’s name so you can even use it in a method for multiple fields.

If the currentValue is ‘0’ meaning false respectevly No we want to hide our 2nd column from the beginning. For that we create a simple dummy checkbox which is not checked and throw it to our event receiver later when the page is rendered. Note that we are currently producing HTML for our columns independently and do not have them present in current page DOM!

Now lets create the 2nd function (Line 31-40):


CUSTOMER.SP.Title.fieldOverrides.getPMTemplateRender = function (ctx) {
var defaultHTML = SPFieldLookup_Edit(ctx);

var parser = new DOMParser();
var docPMTemplate = parser.parseFromString(defaultHTML, "text/html");
var select = docPMTemplate.getElementsByTagName('select')[0];
CUSTOMER.SP.Title.fieldOverrides.pmTemplateID = select.id;

return defaultHTML;
};

Here we create the defaultHTML again, this time for a Lookup column. Afterwards we create a Parser to parse our HTML string. We expect one select in the HTML for our Lookup column (which is indeed a DOM relation but a quite small one). From that select we preserve the ID and store it in our Namespace where we can reference it later in our Event function. (Line 42-50)


CUSTOMER.SP.Title.fieldOverrides.optPMChanged = function (e) {
  var select = document.getElementById(CUSTOMER.SP.Title.fieldOverrides.pmTemplateID);
  if (e.checked) {
	$(select).closest('tr').show();
  }
  else {
	$(select).closest('tr').hide();
  }
};
)

That function is quite simple again. We get our ID from the column to hide we just stored.

Then we have another small DOM dependency as we expect the column in a TR we can hide to hide the whole column line including the Label on the left. But that’s it.

Quite often developer reference columns like this

$('input[title^="Firstname"]')

This is because the Title attribute includes the Display Name of the field. But expect some user with design rights to rename your column and then your code breaks.

The code above can be used in SharePoint Online with classic experience. What could potentially happen that it breaks? The classic form structure using TABLE, TR, TD could be replaced by DIVs and I won’t find my TR to hide anymore. Also, the rendering of a Lookup column could change and the SELECT is not there anymore. In a classic list experience quite unlikely situations.

But nevertheless I am awaiting the new announced [Link] field customization options also for modern experience sites and I assume something not too far away from the CSR Technology.
Update: Referring to a blog entry from Andrew Connell my assumption is not that bad 😉

Finally refer to the whole Code (all funtions):