| Paul's profileAutoSpongePhotosBlogLists | Help |
|
|
May 29 Stop Messing With My Metadata! -- Locking Down Form Fields With JavascriptThis blog assumes you are familiar with techniques to add javascript to a SharePoint page (specifically script that pre-populates fields in a form based on query string parameters), such as in this previous blog. In this example, I have a Course (based on Custom List Item) and a Course Event (based on Event--it's a hidden type but you can work with it) which is an instance of a Course. I also have a list of Course Registrations where people "sign up" for courses. To make reporting easy, I wanted to have both the Course and the Course Event in the Course Registration item's metadata. The instructions on the page were clear (in my mind): "If this is the course you want, click OK." But some people took that to mean they should change the drop down menus and click OK. All that does is raise doubt about which course they actually wanted and cause my reports (standard views with Group By) to be inconsistent. So, how can we lock these fields down? First I tried to use the element attribute disabled. That disabled the form fields, but when the form submitted, the data fields were empty (or using the first option). So I needed a way to keep the values from my query string even if someone changed the field. The answer I came up with is a mash-up of the tested fillDefaultValues function and some new javascript to add events (like onchange) to the form elements. Areas in green are the old fillDefaultValues function. <script type="text/javascript"> _spBodyOnLoadFunctionNames.push("fillDefaultValues"); function fillDefaultValues() { var qs = location.search.substring(1, location.search.length); var args = qs.split("&"); var vals = new Object(); for (var i=0; i < args.length; i++) { var nameVal = args[i].split("="); var temp = unescape(nameVal[1]).split('+'); nameVal[1] = temp.join(' '); vals[nameVal[0]] = nameVal[1]; } setLookupFromFieldName("Course", vals["CourseID"]); setLookupFromFieldName("Course Event", vals["EventID"]); switchback("Course"); switchback("Course Event"); } function setLookupFromFieldName(fieldName, value) { if (value == undefined) return; var theSelect = getTagFromIdentifierAndTitle("select","Lookup",fieldName); if (theSelect == null) { var theInput = getTagFromIdentifierAndTitle("input","",fieldName); ShowDropdown(theInput.id); //this function is provided by SharePoint var opt=document.getElementById(theInput.opt); setSelectedOption(opt, value); OptLoseFocus(opt); //this function is provided by SharePoint } else { setSelectedOption(theSelect, value); } } function setSelectedOption(select, value) { var opts = select.options; var l = opts.length; if (select == null) return; for (var i=0; i < l; i++) { if (opts[i].value == value) { select.selectedIndex = i; return true; } } return false; } 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; } //This function adds an onclick event to the drop down arrow image that fires fillDefaultValues function getDropDownImg () { var downArrow=document.getElementsByTagName('img') for(var i=0; i < downArrow.length; i++) { if(downArrow[i].alt ==('Display lookup values')) { downArrow[i].onclick = fillDefaultValues; } } } //This function adds an event that fires fillDefaultValues function switchback(fieldName){ var switchSelect = getTagFromIdentifierAndTitle("select","Lookup",fieldName); if (switchSelect == null) { var switchInput = getTagFromIdentifierAndTitle("input","",fieldName); switchInput.onmouseup = fillDefaultValues; getDropDownImg(); } else { switchSelect.onchange = fillDefaultValues; } } //--> </script> You'll notice, just like the fillDefaultValues function, we add parameters for our fields. Since fillDefaultValues is being "pushed," these parameters also push our new javascript that adds the new event. In my testing, only IE seemed to change long select lists into inputs. Additionally, the onchange event that MOSS has coded already [onchange="HandleChange()"] doesn't seem to like being overridden so I had to use onmouseup (other events already active in the input element are onfocusout, onkeypress, and onkeydown). Also, because the image element is not really part of the input element, we had to override its event [onclick="ShowDropdown] with our own in the getDropDownImg function. This was tested in IE, FF, and even Safari with great results. You can't "accidentally" change the metadata the page loads with based on the query string. Lastly, we don't want our friendly users mucking with the metadata on the EditForm.aspx page either (but we still want them to be able to delete the item). But my research into the disabled attribute was not in vain. I created another javascript function that is added to disable the select and input elements. Make sure you specify the elements. If you try to disable all input and select elements, you can't access ANY controls, including those in the page's configuration panel. <script type="text/javascript"> _spBodyOnLoadFunctionNames.push("disableForm"); function disableForm () { var disableInput=document.getElementsByTagName('input') var disableSelect=document.getElementsByTagName('select') for(var i=0; i < disableInput.length; i++) { if(disableInput[i].title == "Course" || disableInput[i].title == "Course Event") { disableInput[i].disabled = true; } } for(var i=0; i < disableSelect.length; i++) { if(disableSelect[i].title == "Course" || disableSelect[i].title == "Course Event") { disableSelect[i].disabled = true; } } } //--> </script> As you can see, I was a little sloppier with this and there are two places where each field name needs to be added (since at any time either list could exceed 20 items and switch from a select element to an input). The end result looks like this: Another approach I just thought of includes redirecting the user from the EditForm to the DispForm or change the list definition in SPD. Comments (8)
TrackbacksThe trackback URL for this entry is: http://autosponge.spaces.live.com/blog/cns!D7F85948C20F0293!397.trak Weblogs that reference this entry
|
|
|