Validation on SharePoint Forms – Part Four
Trolling the MSDN SharePoint – Design and Customization forum is proving to be a great learning experience all around. I see questions I can’t answer which cause me to research them, and hopefully, I’m providing some answers which help others.
One of the things I saw over the last few days was a link to a post which explained how to use the PreSaveAction() JavaScript function to validate form data before it is saved. (Check out my recent previous posts about validation in SharePoint forms: Parts One, Two, and Three. I’ve posted about many other bits and pieces of this over time as well.) Greg Osimowicz explains this in a post entitled SharePoint Forms date validation using JavaScript with reference to Edin Kapić‘s post entitled Add JavaScript Date Validation into List Item forms. Read through both posts if you want to see how this holds together.
The cool thing is that there is a JavaScript function called PreSaveAction() which is called by FORMS.JS if it is defined in the form (NewForm.aspx or EditForm.aspx). I had always converted the default List Form Web Part (LFWP) on forms to a Data View Web Part (DVWP) in order to “hook in” my JavaScript into the submit button for validation but it turns out that you don’t necessarily need to do that if you use the PreSaveAction function instead.
So, for example, if you want to validate that a Start Date is before an End Date (as shown in the posts above), you’d add this JavaScript to your page:
<script language="javascript" type="text/javascript"> function PreSaveAction() { var date1 = getTagFromIdentifierAndTitle("INPUT","DateTimeFieldDate","Start Time"); var date2 = getTagFromIdentifierAndTitle("INPUT","DateTimeFieldDate","End Time"); var arrDate1 = date1.value.split("/"); var useDate1 = new Date(arrDate1[2], arrDate1[0]-1, arrDate1[1]); var arrDate2 = date2.value.split("/"); var useDate2 = new Date(arrDate2[2], arrDate2[0]-1, arrDate2[1]); if(useDate1 > useDate2) { alert("The End Date cannot happen earlier than the Start Date"); return false; // Cancel the item save process } return true; // OK to proceed with the save item } // getTagFromIdentifierAndTitle: Find a form field object using its tagName, identifier, and title to find it in the page // Arguments: // tagName: The type of input field (input, select, etc.) // identifier: The identifier for the instance of the fieldName (ff1, ff2, etc.) // title: The title of the list column // function getTagFromIdentifierAndTitle(tagName, identifier, title) { var len = identifier.length; var tags = document.getElementsByTagName(tagName); for (var i=0; i < tags.length; i++) { var tempString = tags[i].id; if (tags[i].title == title && (identifier == "" || tempString.indexOf(identifier) == tempString.length - len)) { return tags[i]; } } return null; } </script>
Hi Marc,
A real basic question – I’ve been reading this post and the references you site as it seems I can use this technique for validating related fields (eg, if a checkbox is true then a related field must be completed also) rather than relying on event handlers on the list. However I’m new to javascript and including it in the list forms. The reference to “Forms.js” has me confused – is this something already included in Sharepoint or do I need to add it (which of course begs the question – where do i get it). thanks
Dan:
Forms.js is one of the JavaScript files that SharePoint uses – in other words, it’s there already. For an example of using the PreSaveAction function in a real world example, check out my article at EndUserSharePoint.com: A jQuery Library for SharePoint Web Services (WSS 3.0 and MOSS): Real World Example – Part 1. It’s jQuery-focused, but you’ll be able to see how it all holds together.
M.
Hi Marc, me again…
I’m trying to use this technique combined with your jQuery library to validate a reservation form. On submit, I want to use a SPServices GetListItems call to fetch the current list of open reservations to make sure the selected reservation hasn’t been filled. I’m getting stuck when I try to make the callback function return True or False. Since the callback is inside the GetListItems function, which is contained in the validate function, I guess I’m missing a link in the ‘return’ chain. I’m also wondering if I should be using “async=false” since really I don’t want anything else happening when I’m validating the form.
DGB
Dan:
Make sure that you define the variable you want to return so that it is scoped properly. for instance, if you want to return the value of myResult:
You *should* use async: false in this case because you need to wait for the result before moving along, as you thought.
M.
Hi Marc,
This works great in SP2010.
My input fields also require to check the time as well as the date. Do you know how to set the date and get the time fields from the column?
Regards,
Adam
Hi Marc,
If you want to add the timestamps into the mix when you have a date/Time format then I have some code that works:
function PreSaveAction() {
var date1 = getTagFromIdentifierAndTitle(“INPUT”,”DateTimeFieldDate”,”Start Date”);
var date2 = getTagFromIdentifierAndTitle(“INPUT”,”DateTimeFieldDate”,”End Date”);
var date1HoursId = date1.id + “Hours”;
var date1Hours = document.getElementById(date1HoursId);
var date1Hour = date1Hours.value.slice(0, -1);
var date1MinutesId = date1.id + “Minutes”;
var date1Minutes = document.getElementById(date1MinutesId);
var date1Minute = date1Minutes.value;
var date2HoursId = date2.id + “Hours”;
var date2Hours = document.getElementById(date2HoursId);
var date2Hour = date2Hours.value.slice(0, -1);
var date2MinutesId = date2.id + “Minutes”;
var date2Minutes = document.getElementById(date2MinutesId);
var date2Minute = date2Minutes.value;
var arrDate1 = date1.value.split(“/”);
var useDate1 = new Date(arrDate1[2], arrDate1[0]-1, arrDate1[1], date1Hour, date1Minute, 0);
var arrDate2 = date2.value.split(“/”);
var useDate2 = new Date(arrDate2[2], arrDate2[0]-1, arrDate2[1], date2Hour, date2Minute, 0);
if(useDate1 > useDate2)
{
alert(“The End Date cannot happen earlier than the Start Date”);
return false; // Cancel the item save process
}
return true; // OK to proceed with the save item
}
// getTagFromIdentifierAndTitle: Find a form field object using its tagName, identifier, and title to find it in the page
// Arguments:
// tagName: The type of input field (input, select, etc.)
// identifier: The identifier for the instance of the fieldName (ff1, ff2, etc.)
// title: The title of the list column
//
function getTagFromIdentifierAndTitle(tagName, identifier, title) {
var len = identifier.length;
var tags = document.getElementsByTagName(tagName);
for (var i=0; i < tags.length; i++) {
var tempString = tags[i].id;
if (tags[i].title == title && (identifier == "" || tempString.indexOf(identifier) == tempString.length – len)) {
return tags[i];
}
}
return null;
}
Adam:
Sorry I wasn’t able to respond more quickly, and I’m glad you figured it out! Thanks for posting your solution to help others.
M.
Hi Marc,
I came across these posts while researching a problem and as usually they are great!
I do have one question that I am trying to confirm. Do the built in SP validations work differently on an unedited page (e.g. NewForm.aspx) with no customization vs. when made into a DFWP for customizations. I am specifically referring to multiple choice Radio Buttons and lookup fields. I have a couple of pages where the required and lookup validation is not working for lookup or multiple choice RB but it works for other fields like datetime and regualar text box. They work as expected in the unedited page. All fields are SharepointListForm fields and I have edited little of the page functionality except converting them so that I have control over look and style. I am going nuts so I am wondering if this is just a SP quirk.
Thanks!
Steve:
The markup which is rendered by a DVWP rather than the default forms is likely to be a bit different, but it’s totally under your control. You’ll need to get very familiar to using the Developer Tools (IE8) or Firebug (Firefox) to see how the elements are rendered in the page so that your script will work.
What is the difference that you are seeing as far as SharePoint’s own validation? Generally, it should work the same.
M.
On the inputs mentioned (lookup and radio button group) the validations don;t work at all. They work for all other inputs on the page. Both work if I use an unaltered form but stop working when I convert it for modification. Both fields are set up to require input.
I went back to some of my older projects and it this problem seems to be consistent; I just had not noticed it until now.
Both fields are standard . The only thing that I modify is the id and any references to it in the id found in the bindings. I give my inputs a proper name such as ffTitle or ffCompany rather than relying on the built in ff1{@Pos} convention. I am wondering if this is messing up how the validation routine finds the control.
Steve:
Try backing out those ID changes. I’m guessing that’s what’s causing the problem. I haven’t ever seen the validations stop working like this.
M.
Backing out to the default SP created input id’s did not work. I must have something really hosed up.
Not sure what it is but since this affects several projects I am going to go for a sure fire method. I am going to use your JQuery library to compare the selected drop down value against the lookup list and fire my own validation.
I would investigate further but I need to get these pages working pretty quick – before anyone notices!
I know this will sound sour but every time I leave SP for a while and work in VS/.net I get very frustrated when I return to SP. Quite frankly your posts and JQuery are what makes working in SP bearable :)
Marc,
Per my previous question I ended up building custom validation for the lookup field using your SPServices/jQuery stuff on Codeplex. It worked well and I want to thank you for your work on that project. Also, congrats on the MVP, your truly deserve it.
The last 3 projects that I have done in Sharepoint were based off of custom forms that I had set up and then kept copying to new projects. Each time I would just change the ListIDs and input bindings. I must have messed up something in the original that has effected validation and it keeps moving to each new project; like a bread pan with a dent in it. When I have time I will figure out what went wrong.
Thanks again!
Steve:
I have a closet full of those bread pans, too. Nothing sticks to them when I cook, but they don’t look very good. ;-) If you have time to pick things apart, I’m sure it’s fixable. You might want to think about storing the XSL in a centrally managed file somewhere rather than copying it over and over. You can then use it in multiple DVWPs using xsl:import. That way, if you have a problem, you fix it once and all is good.
M.
Hii Mark
i have tried doing validation on PreSaveAction method using CEWP but alert inside PresaveAction method is not getting called can u halp me plz
Anil:
There are any number of things which could be going wrong, but it’s hard to say without seeing your code. If a simple alert isn’t firing, then it’s probably a simple syntax error, like a missing semicolon or closing bracket.
M.
Hi Marc. I understyand all that, however, I don’t have two fields to draw from. Only an inout field and todays dat as I’m attempting to validate and ensure if the input date is new Date()) {
alert (alertText);
return false;
}
blah blah..
The problem is it works ok for June 15 being > Juine 8, but it alerts if I enter May 31.??????
Any ideas please??
CW:
I can’t really follow what you’re looking for. It may be that you posted some code which was stripped out?
M.