JSLink Validation – from Basic to Advanced

Custom field validation using JSLink is an extremely powerful beast. In this post I’m going to make an effort to demystify the different levels of validation you can put into your custom template and how to put it together. Everything I’m about to cover has been covered before in different ways and in different combinations. My hope is that this will help separate out what’s needed and what’s not depending on your scenario… so to that end I’ll cover three scenarios. Basic, which will be OOB validation that is custom applied. By that I mean you want to optionally make a field required just like SharePoint does, but you want to control when it’s required.  Custom, which will be a custom validation function that renders its error message just like OOB validation error messages are rendered.  And finally, advanced, where not only do you want to write a custom validation but you want to control how the error state is communicated to the user.

So let’s start at the beginning and we’ll build on the solution from there. First I want to establish the framework for the solution:

Basic

Basic validation is fairly straight forward. You would simply add this code inside of your custom field rendering function (editTaskOwner).

First set up the form context and then create a new “ValidatorSet”:

In the next line we add the new validator to the validation set:

And then lastly, we attach the validation set to the field. In the case of this example I’m using formCtx.fieldName… but this could obviously also be a simple string. I bring this up, because there are limitations on what types of fields you can customize using Custom Templates, namely Taxonomy fields… this is a way to add validation to them from somewhere else in your code.

Note: If you’ve noticed I skipped line 4, more on that later.

The Result

Custom

If you want to write your own validation then you need to do a few extra steps.

Create the custom validation function. This function would go within your validation function but outside of the field custom render function (see the framework at the top)

Modify the RegisterValidator call

 (Optional) Depending on how you render the field you may have to add the following code. What I mean by that is if you use one of these OOB field rendering functions you do not need this line, if you develop your own layout then you will need this to “attach” the error message to the right object in the DOM. In this example my custom people picker field is rendering html wrapped with <div id=”TaskOwnerDiv”></div>. So I need to reference the div’s ID in the SPFormControl_AppendValidationErrorMessage call.

The Result

Advanced

So, if that didn’t seem advanced enough for you, the last scenario is that you may want to customize how the “error” is displayed to the user. Maybe you want to display an image, or collect all the validation messages into one area. That’s possible by doing the following:

Write custom error rendering code. This code needs to be completely outside of the custom rendering template code. Here’s a really basic example.

Modify the registration of the error callback, which causes your custom function to be fired if the isError flag is true.

The Result

So, as you can see custom form validation is extraordinarily powerful with Custom Templates and can allow you to really take SharePoint to the next level.

JSLink Custom User Field Schema

I had the requirement of setting the default value of a person field to the current user.  After looking around in the great wide internet I found a very helpful article by Glenn Reian which got me started.

Where I ran into a problem was that my user field had customized settings that weren't being pulled through into the custom implementation of my people picker.  As it turns out the issue was with the schema that is passed to the SPClientPeoplePicker_InitStandaloneControlWrapper function.  In Glenn's example (and every other example I found out there) this schema is hard coded, which is perfectly acceptable in most cases.  However, I needed some values to be slightly different to adhere to my column settings.  

As it turns out there are two solutions.  The first, obvious one, is to adjust the schema manually in the code.  And again this may be a fine solution.  But as Glenn did, I had separated my concerns and created what I hoped to be a fairly reusable version of initializePeoplePicker.  So now I needed to enhance that function to pass through adendums to the schema or maybe it's own schema.

What I found was something i wasn't quite expecting.  The schema I needed was actually right there in the context variable in JSLink.  So, using Glenn's implementation and extending it slightly I just modified initialzePeoplePicker to the following: 

var initUserDefaultPeoplePicker = function (ctx, peoplePickerElementId, ppSchema) {
    if (ppSchema === null) {
        ppSchema = {};
        ppSchema['PrincipalAccountType'] = 'User';
        ppSchema['ShowUserPresence'] = true;
        ppSchema['SearchPrincipalSource'] = 15;
        ppSchema['ResolvePrincipalSource'] = 15;
        ppSchema['AllowMultipleValues'] = false;
        ppSchema['MaximumEntitySuggestions'] = 50;
        ppSchema['Width'] = '280px';
    }
    var uri = _spPageContextInfo.webAbsoluteUrl + "/_api/SP.UserProfiles.PeopleManager/GetMyProperties";
    getAjax(uri).done(function(user) {         
        // Set the default user by building an array with one user object
        var users = new Array(1);
        var currentUser = new Object();
        currentUser.AutoFillDisplayText = user.DisplayName;
        currentUser.AutoFillKey = user.AccountName;
        currentUser.Description = user.Email;
        currentUser.DisplayText = user.DisplayName;
        currentUser.EntityType = "User";
        currentUser.IsResolved = true;
        currentUser.Key = user.AccountName;
        currentUser.Resolved = true;
        users[0] = currentUser;         // Render and initialize the picker
        SPClientPeoplePicker_InitStandaloneControlWrapper(peoplePickerElementId, users, ppSchema);
    });
};
and then from the custom rendering function for the user field I passed the schema associated with the field through:
function efTaskOwner(ctx) {
    var retVal = '<div id="TaskOwnerDiv">';
    retVal += initDefaultPeoplePicker(ctx.CurrentItem["TaskOwner"], 'TaskOwnerDiv', tx.CurrentFieldSchema)
    retVal += '</div><span class="etmRequiredField"></span>';     
    return retVal;
}

SharePoint 2013 JSLink – All Fields Rendered

While creating a custom Client Template using JSLink, I came up against the issue of knowing when all the fields were rendered on the form.  To explain where the issue arises let me first take just a moment to explain when building a custom template for this type of form, where you want to manipulate the fields, you have available to you both a Pre and Post Render function.  What that does is fire the function attached to it either pre or post each custom field rendering being executed.

The reason I bring this up is that there could be some misconception that it fires before field rendering starts and after all field rendering is complete, but that’s not the case. So if your form has 10 fields, these functions will each fire 10 times.  I also found document.ready to be unreliable as it often fired before all the fields were rendered, and further, if I needed to make decisions based on the context of the form, I would no longer have access to that information.

So, the solution does in the end involve the OnPostRender function of the Template Override, but what you do there is what counts. So just to put everything in context, and for brevity, here is the shell of the custom Client Template file.  Note the declaration of the postfields variable inside of My.CustomTemplate.

Ok, now we need to fill in the onPostRenderTemplate function.  Primarily, we need to know when we’ve gotten through all the fields on the form. This is accomplished by incrementing the "global" postfields variable within the onPostRenderTemplate function.  The question is what are we testing it against to know when we've rendered all the fields.

The answer is JavaScript prototype function keys which seems to be fairly well supported.

The Object.keys() method returns an array of a given object’s own enumerable properties, in the same order as that provided by a for...in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well).

Ergo, if you look at the ctx.Template.Fields and get the length that gives you the number of Fields on the form that will be "rendered" and provides you a way of telling when the last Field has been rendered.

So now I can execute some fancy functions to do thinks like:

Hide Fields

Modifying the Fields label to make it look like it was Required

or some other post rendering customization based as I stated on values in the ctx variable.