Validation on SharePoint Forms – Part Two

In my previous post I outlined a few approaches to validation in SharePoint forms.  In this post, I’ll give some simple examples of how you might validate some date inputs.  For this example, I’m using a little Paid Time Off (PTO) application I built for one of my clients.  The basic idea was that the employees could make a request for time off, and the request could be approved or denied by their manager (using SharePoint Designer-based workflow).  There was some reporting around all of this as well.

I built a  List called Requests for PTO, and of course got the default forms (NewForm.aspx and EditForm.aspx).  On both forms, I converted the List Form Web Parts (LFWPs) to Data View Web Parts (DVWPs) so that I could better control their layout.  (This was due to some other requirements I won’t cover here.  The same scripting below would work on the default LFWP with a few tweaks.)  There were several more changes which the client wanted to make to those forms:

  • The client had offices in the US and UK, so whatever the date format, it confused half the population, so they wanted to require use of the date picker control rather than allowing direct date entry.
  • They wanted to cleanly track PTO within calendar years, so no one request could cross year boundaries.
  • Start Date and End Date were required, but also should indicate a valid range.

Let’s focus on the second bullet above.  I added my helper functions to the page by including a source .js file to it.  I usually create a Document Library at the root of the Site Collection called JavaScript to contain these files for centralized editing and reuse.  So in the page, I added the following script tag:

<asp:Content ContentPlaceHolderId=”PlaceHolderAdditionalPageHead” runat=”server”>
    <META Name=”CollaborationServer” Content=”SharePoint Team Web Site”>
    <script type=”text/javascript” src=”/JavaScript/Utilities.js”></script>

Note the location of this script tag: right at the top of the asp:Content area called PlaceHolderAdditionalPageHead.

Next, I added in the code which was specific to the page directly, taking advantage of my helper functions.  (In the code below, I’ve included my helper functions inline to make following along easier.  I also have left in some commented out debugging lines which I’ve found helpful to understand exactly what’s going on.  This example is from NewForm.aspx.)

// Validate the PTO Request input
function validateInput() {
    startDate = getValueWithFieldName('input', 'Request Start Date', 'ff1_new');
    endDate = getValueWithFieldName('input', 'Request End Date', 'ff2_new');
    //alert(startDate + endDate);
    startYear = startDate.substring(startDate.length, startDate.length - 4);
    endYear = endDate.substring(endDate.length, endDate.length - 4);
    //alert(startYear + endYear);
    if(startYear != endYear) {
        return 'Start date and end date must be in the same year.  To enter a PTO request which crosses into the next year, please enter two requests.';
    if(startDate.length == 0) {
        return 'Please enter a start date.';
    if(endDate.length == 0) {
        return 'Please enter an end date.';
    return '';

// getValueWithFieldName: Get a form field value using its tagName, fieldname, and identifier to find it in the page
// Arguments:
//        tagName:    The type of input field (input, select, etc.)
//        fieldName:    The name of the list column
//        identifier:    The identifier for the instance of the fieldName (ff1, ff2, etc.)
    function getValueWithFieldName(tagName, fieldName, identifier) {
        //alert('getValueWithFieldName: tagName=' + tagName + ' fieldname=' + fieldName + ' identifier' + identifier);
        var theInput = getTagFromIdentifierAndFieldname(tagName, fieldName, identifier);
        //alert('getValueWithFieldName:' + + ' theInput.value=' + theInput.value);
        return theInput.value;

// getTagFromIdentifierAndFieldname: Get an input field's tag object using its tagName, fieldname, and identifier to find it in the page
// Arguments:
//        tagName:    The type of input field (input, select, etc.)
//        fieldName:    The name of the list column
//        identifier:    The identifier for the instance of the fieldName (ff1, ff2, etc.)
    function getTagFromIdentifierAndFieldname(tagName, fieldName, identifier) {
        //alert('getTagFromIdentifierAndTitle: tagName=' + tagName + ' fieldname=' + fieldName + ' identifier' + identifier);
        var len = identifier.length;
        var tags = document.getElementsByTagName(tagName);
        for (var i=0; i < tags.length; i++) {
            if (tags&#91;i&#93;.title == fieldName) {
                //alert('HIT tags&#91;' + i + '&#93;.title' + tags&#91;i&#93;.title + ' tags&#91;' + i + '&#93;.id=' + tags&#91;i&#93;.id + ' identifier=' + identifier);
                if((tags&#91;i&#93;.id == identifier) || (tags&#91;i&#93;.id.indexOf(identifier) > 0)) {
                    return tags[i];
        return null;

In my form, I altered the onclick event on the Submit button, like so:

<td nowrap="" class="ms-vb">
    <input type="button" value="Submit" name="btnSubmit">
     <xsl:attribute name="onclick">
      errmsg = validateInput();
      if(errmsg.length > 0) {
      } else {
       <xsl:value-of select="ddwrt:GenFireServerEvent('__commit;__redirectsource')" />
    <input type="button" value="Cancel" name="btnCancel" onclick="javascript: {ddwrt:GenFireServerEvent('__cancel;__redirectsource')}" />

The validateInput JavaScript function does three tests:

  • Ensures that Start Date and End Date fall in the same year
  • Ensures that the Start Date is not blank
  • Ensures that the End Date is not blank

If any of these tests fails, the function returns a string with a message to the user.  The script on the button’s onclick event then either shows an alert with that message or commits the change if all is well.  The same approach works on the EditForm.aspx page, with a few tweaks to take into account the slightly different structure of the LFWP or DVWP.

Validation on SharePoint Forms – Part One

There are many occasions where you might like to do some validation on NewForm.aspx and/or EditForm.aspx in SharePoint beyond the simple column by column validation which the form provides automagically.  For instance, if you have two dates, you might want to ensure that the second is after the first, or you may want the entry of a value in one column to change the available values in another.  The .NET folks out there will want to jump straight into Visual Studio, and there’s nothing wrong with that.  However, there are some nice options using SharePoint Designer (what I call the “Middle Tier”) as well.

One set of options doesn’t require any change to the List Form Web Part (LFWP) which is on the page by default.  Using JavaScript, you can hook into the events on the controls (onchange, onclick, etc.) to do some validation.  I started learning about this by reading the great post over at the Microsoft SharePoint Designer Team Blog entitled Using JavaScript to Manipulate a List Form Field.  In that post, they provide some nice JavaScript functions to get you started.  I soon found that I needed to do other things and started to add to and extend some of the functions found there.  I’ve now got a little toolkit of functions that I use to build from.

The second set of options entails converting the LFWP to a Data View Web Part (DVWP) and reconfiguring the controls themselves.  This is relatively easy, and lets you totally reconfigure the page to your heart’s content.  You sometimes can do this by clicking on the icon in the upper left of the LFWP and choosing Convert to XSLT Data View.  (There are plenty of posts out there on how to do this step – Live Search “Convert to XSLT Data View”.)

I’ve been participating in the MSDN/TechNet forums on SharePoint – Design and Customization a lot lately, and there is a lot of interest in these techniques, perhaps due to the fact that SharePoint Designer is now freely available.

In this series of posts, I’ll explain some of the approaches which I’ve used.  Next up: the date check example above.

SharePoint Document Library Headscratcher

Here’s a head-scratcher for you…

In a SharePoint Document Library where you have Versioning and Check In/Check Out enabled, when you first upload a document, the “save” button on EditForm.aspx is labeled “Check In” and saves and also checks the document in (good). On a subsequent edit of the metadata (properties), you’re forced to check the document out again (good), but the “save” button is labeled “OK” and doesn’t check the document in (maybe good, maybe bad). Now I can see where this is a good thing because the user might want to fiddle the document a few times before they check it in. But what if you want to be sure they check it in?

It surely is by design, but in this case, the design isn’t what we want!

We have over 20 Content Types stored in one list, and we don’t want to give up the great capability that is there out of the box where the EditForm.aspx is “Content Type aware”. (When you switch Content Type, the form automagically adjusts the columns.) So I was thinking about using script to add a new Check In button to replace the OK button.  I’ve already got a lot of script on the page (of course it’s a custom version of the form called EditFormCustom.aspx — never edit the original!) that enforces business rules around the metadata interdependencies.

Alternatively, I was also thinking of redirecting on every save to a dashboard page where the user could see all of their docs and their disposition (a la My Site) so that they could manage them there.

Any other ideas?  (Short of writing a lot of crufty C# code.)

Setting Multi-Select Widths in a SharePoint EditForm.aspx Using JavaScript

<UPDATE date=”2009-01-25″>
I now have a function in my jQuery Library for SharePoint Web Services called SPSetMultiSelectSizes which accomplishes this in a more robust way, taking into account the font, font size, etc.

When you have a multi-select lookup column in a list, SharePoint provides you with a control that shows two select boxes next to each other on EditForm.aspx.  There are two buttons (‘Add >’ and ‘< Remove’) that let you move values between the two, selecting or deselecting the values.

By default, the select boxes are a fixed width and, in many cases, not wide enough to let your users see the values very well.  The following JavaScript will set the widths of the select boxes based on the length of the longest value available in the lookup.  It isn’t fully multipurpose, as I wrote it for a specific instance with a particular set of branding (font size, spacing, etc.) but it ought to give you a very good start to use it yourself.  (With the fonts that I was using, I found that 7 times the number of characters in the longest value worked well to calculate the right width.  You’ll probably need to experiment.)  Pass in the name of the column you want to adjust.

// setSelectWidth: Set the width of a lookup column's select box based on the values it contains
// Arguments:
// columnName: The name of the column which is being displayed in the select box
function setSelectWidth(columnName) {

  var charFactor = 7; // Approximate pixels per character

  // Left side
  leftColumnSelect = getTagFromIdentifierAndTitle("select","",columnName + " possible values");
  if(leftColumnSelect != null) {
       leftColumnSelectDIV = findParentElement(leftColumnSelect, "DIV");

  // Right side
  rightColumnSelect = getTagFromIdentifierAndTitle("select","",columnName + " selected values");
  rightColumnSelectDIV = findParentElement(rightColumnSelect, "DIV");

  // Find the longest value
  var longestValue = 0;
  for (var i=0; i  leftColumnSelect.options.length; i++) {
    if(leftColumnSelect.options[i].text.length > longestValue) {
      longestValue = leftColumnSelect.options[i].text.length;
  for (var i=0; i < rightColumnSelect.options.length; i++) {
    if(rightColumnSelect.options[i].text.length > longestValue) {
      longestValue = rightColumnSelect.options[i].text.length;

   // Set the widths of the two selects and their containing DIVs
   var newWidth = charFactor * longestValue; = newWidth; = newWidth; = newWidth; = newWidth;

This function builds on the getTagFromIdentifierAndTitle function provided in an excellent blog post I’ve referenced before over at the Microsoft SharePoint Designer Team Blog.  I’ve also created a findParentElement function you’ll see called above, which finds a specific parent element for a tag.  The code for this is below:

// findParentElement: Find an object's specified parent element
// Arguments:
// thisElement: The element you want to search from
// parentTag: The parent tag you want to find

function findParentElement(thisElement, parentTag) {
  var currentElement = thisElement;

  while(currentElement.tagName != parentTag) {
    currentElement = currentElement.parentNode;

    if(currentElement.tagName == parentTag) {
      //alert('HIT:' + currentElement.tagName);
      return currentElement;
  return null;

Get a People Picker’s Current Value on a Form

There’s a nice article over at the SharePoint Designer Team Blog about how to manipulate a List Form Field (AKA Data Form Field) using Javascript.  It gives some great methods to accomplish this, but if you’d like to get the current value of a People Picker on a form (for validation purposes, most likely), the info isn’t there to do so reliably.  I had to do this today, so I wanted to post what I came up with. As usual when I post these things, I’ve left in the alerts that I used for debugging in case it helps you.

// Find a People Picker’s value using its identifier (ff1, ff2, etc.)to find it in the page
function getPickerInputElement(identifier) {
  var tags = document.getElementsByTagName(‘DIV’);
  for (var i=0; i < tags.length; i++) {    var tempString = tags[i].id;    //alert('tags[' + i + '].id = ' + tempString);    if ((tempString.indexOf(identifier) > 0) && (tempString.indexOf(‘UserField_upLevelDiv’) > 0)){
    //alert(‘HIT for ‘ + identifier + ‘ id=’ + tags[i].id + ‘ value=’ + tags[i].value);
    var innerSpans = tags[i].getElementsByTagName(“SPAN”);
    for(var j=0; j < innerSpans.length; j++) {      //alert('innerSpans[' + j + '].id = ' + innerSpans[j].id);      if(innerSpans[j].id == 'content') {       //alert('HIT for ' + identifier + ' id=' + innerSpans[j].id + ' innerHTML=' + innerSpans[j].innerHTML);       return innerSpans[j].innerHTML;      }     }      }   }   return null;  }[/sourcecode]