Using Javascript to Manipulate a List Form Field

Using Javascript to Manipulate a List Form Field

Rate This

Hi, my name is Rob Howard, and I’m a Program Manager with the SharePoint Designer team. Like several of the other people posting here, I also built many of the Application Templates for Windows SharePoint Services.

If you’re familiar with them, you may have noticed that in several of the application templates we use a bit of Javascript to set default form values based on the query string. Because we found this to be useful in many different cases throughout our applications, I wanted to share our method with you guys so that you can include it in the applications you develop.

When might you use this?

It’s pretty easy to set a field’s default value through the list settings in the browser UI, so why might you need Javascript to set a default field value? The reason is that field default values can only take static values or simple formulae based on the current user or today’s date. If that meets your needs, then I’d definitely recommend sticking with that method. Sometimes, though, you may want the form to fill with default values based on the user’s interaction with the previous page, and that’s exactly where this method comes in.

How does it work?

In short, we add some Javascript to the page that runs when the body is loaded. This Javascript parses the page’s query string, locates the HTML objects that are rendered by the relevant SharePoint fields, and sets their value based on the information in the query string.

getTagFromIdentifierAndTitle

The most important part of our solution is the “getTagFromIdentifier” function. This function finds the HTML element rendered by a given SharePoint FormField control. It takes the following parameters:

  • tagName – The name of the tag rendered in the form’s HTML
  • identifier – The string associated with the SharePoint type of the relevant field
  • title – The value of the relevant HTML tag’s “title” attribute, which also matches the field’s display name

Here’s a partial table of SharePoint column types and their corresponding “identifiers” and “tagNames”:

SharePoint Field Type identifier tagName
Single Line of Text TextField input
Multiple Lines of Text TextField input
Number TextField input
Currency TextField input
Choice (dropdown) DropDownChoice select
Lookup (single)* Lookup select
Lookup (multiple) SelectCandidate; SelectResult select
Yes/No BooleanField input

*Lookups are a bit more complicated because Lookup FormFields render differently when the target list contains more than 20 items. See the end of the post for an example.

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;

}

fillDefaultValues

Now that we have the HTML elements that we want to set, we need the values with which to set them. In our solution, we wrote the “fillDefaultValues” function, which parses the page’s querystring and then uses the values to set the field defaults.

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];

  } 

  // Set HTML element default values here

}

_spBodyOnLoadFunctionNames

In most cases SharePoint pages are based on a master page that contains the “body” element. These content pages can’t directly add a function to the body’s onload event. In order to work around this limitation, SharePoint provides the “_spBodyOnLoadFunctionNames” array. When the body is loaded, the onload event handler executes each function whose name is contained in this array. We added “fillDefaultValues” to the array so that it would run when the body’s onload event fires.

_spBodyOnLoadFunctionNames.push("fillDefaultValues");

All Together Now

With the script above, you can set most different field types to any value from the querystring – or any other source that javascript can access. Below is a full example of the script we use to set the default value of a Lookup field based on an ID stored in the querystring. You’ll notice that setting a Lookup field is a bit more complicated than some other field types. The reason is that Lookup FormFields are rendered with different HTML when the target list contains more than 20 items.

Enjoy!

<script type="text/javascript">

 

// This javascript sets the default value of a lookup field identified

// by <<FIELD DISPLAY NAME>> to the value stored in the querysting variable

// identified by <<QUERYSTRING VARIABLE NAME>>

 

 

// Customize this javascript by replacing <<FIELD DISPLAY NAME>> and

// <<QUERYSTRING VARIABLE NAME>> with appropriate values.

// Then just paste it into NewForm.aspx inside PlaceHolderMain

 

_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("<<FIELD DISPLAY NAME>>", vals["<<QUERYSTRING VARIABLE NAME>>"]);

}

 

function setLookupFromFieldName(fieldName, value) {

  if (value == undefined) return;

  var theSelect = getTagFromIdentifierAndTitle("select","Lookup",fieldName);

 

// if theSelect is null, it means that the target list has more than

// 20 items, and the Lookup is being rendered with an input element

 

  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;

}

</script>

  • the following values for a people picker field do not seem to work - something am missing perhaps - did anyone encounter this?

    tagName = "textarea"

    identifier="TextField"

    title="People Picker"

    (the 'Title' property for this textarea seems to be hard coded to 'People Picker' and not the display name)

  • You could add this function to set the value of a text field:

    function setTextFromFieldName(fieldName, value) {

     if (value == undefined) return;

       var theInput = getTagFromIdentifierAndTitle("input","",fieldName);

    theInput.value=value

    }

  • 2 questions

    Is there a similar command to _spBodyOnLoadFunctionNames.push for onSubmit that can be fired when a user checks a page back in? I need to do some date checking (date C cannot be before date B which cannot be before date A etc...)

    Also, I how can I check for and prevent duplicate titles from being added (with document version control on)?

    I have tried using the ItemUpdating event (see code below).  When I get a hit the condition arises

    I get a message of

                           properties.ErrorMessage = "Title already exists in category: " & duplicateCategoryName

                           properties.Cancel = True

    and set the cancel property -

    Control passes back to the screen and prompts the user to Exit without Saving, but the values already saved.  

    The user can click Exit w/o saving and we are still getting duplicates in the Title field.

    This looks to be a bug, but I am not sure... we also need check the title at ItemAdding and that hasn't worked either.

    --------------------------------

    CODE SAMPLE

    --------------------------------

     Public Overloads Overrides Sub ItemUpdating(ByVal properties As SPItemEventProperties)

           Try

               Dim webCollection As SPWebCollection

               Dim strSiteURL As String = properties.WebUrl

               Dim siteCollection As New SPSite(strSiteURL)

               siteCollection.AllowUnsafeUpdates = True

               Dim site As SPWeb = siteCollection.OpenWeb()

               site.AllowUnsafeUpdates = True

               webCollection = site.Webs

               Dim pageTitle As String = ""

               Dim pageItem As SPListItem = properties.ListItem

               Dim pageSynopsis As String = ""

               If pageItem.Level = SPFileLevel.Draft Then

                   If Not pageItem("Title") Is Nothing Then

                       pageTitle = pageItem("Title")

                       Dim topLevelSite As SPWeb = site

                       Do While Not topLevelSite.ParentWeb Is Nothing

                           topLevelSite = topLevelSite.ParentWeb

                       Loop

                       Dim currentPage As Guid = New Guid(pageItem("GUID").ToString())

                       If isTitleDuplicate(topLevelSite, pageTitle, currentPage) Then

                           properties.ErrorMessage = "Title already exists in category: " & duplicateCategoryName

                           properties.Cancel = True

                       End If

                   End If

                   If pageItem.ContentType.Name = "New NCCI Articles" Then

                       If Not pageItem("ArticleSynopsis") Is Nothing Then

                           pageSynopsis = pageItem("ArticleSynopsis")

                           If pageSynopsis.Equals("") Then

                               properties.ErrorMessage = "Synopsis is a required field"

                               properties.Cancel = True

                           End If

                       Else

                           properties.ErrorMessage = "Synopsis is a required field"

                           properties.Cancel = True

                       End If

                   End If

               End If

           Catch ex As Exception

               properties.ErrorMessage = "Error in ItemUpdating: " & ex.ToString()

               properties.Cancel = True

           End Try

       End Sub

  • It works well, is there somewhere to find a complete list of Sharepoint Columns & Identifiers?  I'm specifically looking for multiple selection, not a dropdown list select.

    thanks,

    jt

  • Can someone indicate on which page in which application template this is used? As such I can look at a real life example.

  • An example of the Application Template is the Job Requisitions Server Admin Template.  In the list Candidates, the DispForm.aspx uses Data Views to show items from the Interview Calendar related to the display item.  There is then the link to add a new Interview by passing the user to NewForm.aspx in the Interview Calendar list.  This is where the javasript above lives.

    ~Jeff K

  • Will this script work when using the Office SharePoint Designer to create a workflow?  I get an error message when I try and add any script to the page.

  • Hi,

    Great post: I managed to elaborate something similar on other pages.

    One question.

    On the example template, you can schedule an interview on the candidates dispform.aspx page. This gives the CandidateId as querystring parameter to the next target screen where it is used as input to determine the value of a dropdown box.

    In my environment I have set up something similar, but I want to give an additional parameter to the following target page, which is used as input for a second dropdown box. My problem is that the second parameter is a lookup field to a list. I managed to pass the value through the target page, but in fact it shouldn't give the value which is displayed on the screen, but the ID of the value in the lookup list. How can I get the ID of that lookup field and pass it through?

    Additionally: will the script mentioned here be able to handle two parameters at the same time to determine the dropdown values in the second target page?

  • Can you please give the tag name and identifier for Person/Group field? I need to hide a UserField for my NewForm.aspx. I tried using the multiple Lookup for SharePoint Field Type, but it doesn't work. I also tried few other combinations but no use. Please help.

  • There are many choices to customize lists in SharePoint 2007, but one of the more useful techniques is

  • There are many choices to customize lists in SharePoint 2007, but one of the more useful techniques is

  • Hi, I've seem many examples of having a query string item populate a field and java script is a popular answer. It boils down to getting the java script into the aspx page.

    My problem is, the newform.aspx page has no where to put the java script. There is no html in it..

    This article says there is a _spBodyOnLoadFunctionNames  function but I can not find that....

    Basically, I create a custom list... I then use sharepoint designer to go to the newform.aspx file for that list.

    The code in the page begins with:

    <%@ Page language="C#" MasterPageFile="~masterurl/default.master"

    ........

    ........

    I was able to get around this by detaching the page from the masterpage. That seems to show the html code, but I don't want to do that, and this article doesn't allude to that...

    Can someone help me out on this? Basically, I have no idea where to stick the java script and get it to run base on my situation... I'm confused that I can't find others with this issue...

    Help, please..

  • Hi nevillew,

    Jeff said:

    An example of the Application Template is the Job Requisitions Server Admin Template.  In the list Candidates, the DispForm.aspx uses Data Views to show items from the Interview Calendar related to the display item.  There is then the link to add a new Interview by passing the user to NewForm.aspx in the Interview Calendar list.  This is where the javasript above lives.

    Look at this page and you'll see they use a Content Editor Web Part. Insert this web part and you can insert code onto the page.

  • Hi, thanks for your response. Sorry, I'm still a bit confused...I do appreciate your help very much....

    I'll go through my steps and then list some problems..

    1) I create a custom list called test.

    2) I create columns Column1, Column2 and Column3.

    3) I then go into SharePoint designer and browse to the list. In the list I see the following aspx pages.

       AllItems.aspx, DispForm.aspx, EditForm.aspx and NewForm.aspx.

    4) Now, what I want is to be able to do isretrieve data from the url and store it in a field, when the user

       loads NewForm.aspx

    The 2 things I notice (while using SharePoint Designer is)

       a) In display view, the controls are not visible. It shows a standard display.

           Refer to http://blog.henryong.com/2007/09/05/how-to-edit-the-form-fields-of-a-sharepoint-list/

       b) When I look at code view, I see aspx code. I don't believe I can stick my java script in here,              

           although from some other sites I read, they imply I can.

    Now, this article makes reference to my situation saying that the newform.aspx page is the content page and there is a master page which is used in conjunction with the content page...

    The article mentions a function: _spBodyOnLoadFunctionNames but I can't find out where to locate this...

    You would think I could google it and get a hundred hits but there is not much on this....

    I also need a solution that is modular. I.e only effects this list.

    So basically, that is my situation... I'm not sure why thisn isn't confusing others here....

    I was able to achieve something by creating a new aspx page and then importing sharepoint content into it.

    This created a page that was detached from a master page. It contained <Head> ... etc....

    The problem with this method is, it is too much overhead to support these new pages...

    I also tried to back them up and restore them but I think because of unique identifiers in the page

    it caused issues...

    Basically, I've found that trying to get a query string variable into a field causes to much damn pain that its just better to have the user imput the value, although this drives me crazy. You'd think there would be a more simpler out the box way to do this (and please correct me if I am wrong).

    So, based on the above can you help me out... Maybe I'm just going off in the wrong direction, but something tells me there is more to this than what this blog states.....

    PS, why is the interace for entering comments into this blog so crappy? I'm not complaing, but come on...

  • Neville

    You're not too far off. To execute the code on the newitem.aspx page of this one list, just insert a script tag (pretty much anywhere near the bottom), I generally put them near another script tag and then insert the call to _spBodyOnLoadFunctionNames and then the functions your want called

    Insert this code

    <script>

    _spBodyOnLoadFunctionNames ("Bob");

    function Bob() {alert('Hello World'};

    </script>

    When the page loads you get the alert box.

    Hope this helps

Page 2 of 12 (167 items) 12345»
Leave a Comment
  • Please add 7 and 2 and type the answer here:
  • Post