Search This Blog

Tuesday, December 14, 2010

SharePoint Form Dynamic Field Hide or Reveal Using JavaScript

1. From time to time a customer asks for fields to be dynamically hidden or revealed on the SharePoint EditForm.aspx or NewForm.aspx. One the most versatile and effective ways to accomplish this is by using the Content Editor Web Part and JavaScript. In this article I will guide you through configuring and developing this kind of functionality.

2. Here is our scenario; we need to add dynamic capability to a custom task form so that when the user edits the task form and chooses to reassign a task the hidden Reassignment Reason Multi-Line Text field is revealed. Our custom task form will have a customized Task Status field and an additional custom field, Reassignment Reason, as shown below:

a. Task Status (Choice)
  • Assigned
  • In Progress
  • Completed
  • Reassign 
b. Reassignment Reason (Multiple Lines of Text)

3. So the first question you may be asking is “How do I add a CEWP to the Edit and New forms?” I’m glad you asked! While the New and Edit forms do not provide an interface to access to the Edit Page function in the Site Actions menu, you can still get access to this capability through the browser by appending the following query to the end of the URL string for the New and Edit forms:

&pageview=shared&toolpaneview=2 

4. OK, so now that you can see the Edit Page interface of the Task Form lets add a CEWP in the usual way, just click on the “Add a Web Part” control at the top of the Web Part Zone and then from the Webpage Dialogue scroll down to the Miscellaneous section and choose Content Editor Web Part. Now click on the Add button at the bottom of the dialogue page and the CEWP will be added to the page.

5. Now click on the edit button of the CEWP in the Web Part Zone and choose the menu option “Modify Shared Web Part”. This will bring up the web part configuration interface in the right panel. From this interface click on the Source Editor and the text entry dialogue box will open. This is the area where you will need to write your code. We aren’t going to write any code right now though, so you can close the dialogue box.

6. Now we have to talk about the special JavaScript function we will need to use in order to “discover” the SharePoint controls in the task edit page – this function is called “getTagFromIdentifierAndTitle” and it is displayed below:

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; 


7. According to Microsoft this JavaScript function “parses the page’s query string, locates the HTML objects that are rendered by the relevant SharePoint fields, and sets their value.” The function can identify the fields by matching three parameters:

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

8. While the title parameter is easy to obtain, one of the challenges you will often face when using this script is finding the tagName and identifier parameters. Microsoft provides a partial list as a starting point - see this tech net article:

http://blogs.msdn.com/b/sharepointdesigner/archive/2007/06/13/using-javascript-to-manipulate-a-list-form-field.aspx

9. However, there is another way to find this information, by using a very handy tool set that comes installed with Internet Explorer 8, and which Microsoft has very cleverly named “Developer Tools”. To activate the Developer Tools in IE, press F12 or use the "Tools" – "Developer Tools" menu. To find out more information about any element, click on the “Select Element” arrow in the tool set, and then select the element on the page. The tool set will take you to that elements markup and code and provide a great deal of information about that element to include the identifier and tag name. (If you don’t have the option of updating IE to 8 or higher, with IE7 you can use Developer Toolbar for Internet Explorer.)

10. OK, so now we need to create our function to hide the Reassignment Reason field when the user opens the page. Here is our basic function outline:

_spBodyOnLoadFunctionNames.push("hideField"); {   
var theInputMLTRR = getTagFromIdentifierAndTitle("TextArea","TextField","Reassignment Reason");  
//*** Hide the Field ***  
function hideField() 

   theInputMLTRR. parentNode.parentNode.parentNode.style.display = "none";
}  

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


 a. spBodyOnLoadFunctionNames.push() – This is a built in SharePoint function that will allow you run a function when the page loads. This will be very useful to us because we want to hide the Reassignment Reason field before the form is viewed by the user. 
b. Script Variables – We need to set one variable, the Multi-Line Text Reassignment Reason. This variable will be set using the getTagFromIdentifierAndTitle function
c. style.display – setting this control property to “none” will hide the control from the user.

 11. Now we have to find a way to reveal the control if the user selects the custom task status choice “Reassign” (as well as a way to hide it back if she changes her mind and chooses another task status after the field is revealed). Here is our next bit of code, our revealField() function:

//*** Reveal the Field *** 
function revealField() 

   theInputMLTRR .parentNode.parentNode.parentNode.style.display = "";
}

12. All we need now is a way to capture the onChange() event for the custom Task Status field:

var theChoice = getTagFromIdentifierAndTitle("TextArea","TextField","Reassignment Reason");  
getTagFromIdentifierAndTitle("TextArea","TextField","Reassignment Reason").onchange = function(){revealHideControl()};  

//*** Reveal the Field *** 
function revealHideControl(){  
if (theChoice.value == 'Reassign') { 
revealField(); 
}else 

hideField(); 



13. All we have to do now is copy our script into the CEWP, so let’s go back to the web part configuration interface in the right panel. From this interface click on the Source Editor and the text entry dialogue box will open. Now just copy and paste the code below into the text box and click “Save” which will close the dialogue box. From the right panel interface click “OK” and then from the EditForm.aspx click OK again, and your form is ready to test.

_spBodyOnLoadFunctionNames.push("hideField"); {  
var theInputMLTRR = getTagFromIdentifierAndTitle("TextArea","TextField","Reassignment Reason");  

//*** Hide the Field *** 
function hideField() 

theInputMLTRR. parentNode.parentNode.parentNode.style.display = "none"; 
}  

//*** Reveal the Field *** 
function revealField() 

theInputMLTRR .parentNode.parentNode.parentNode.style.display = ""; 
}  

//*** Capture the Change Event *** 
var theChoice = getTagFromIdentifierAndTitle("select","DropDownChoice","Task Status");  
getTagFromIdentifierAndTitle("select","DropDownChoice","Task Status")onchange = function(){revealHideControl()};  

//*** Reveal or Hide the Field *** 
function revealHideControl()
{  
   if (theChoice.value == 'Reassign')
   { 
      revealField(); 
   } 
   else 
  { 
      hideField(); 
  } 


//*** getTagFromIdentifierAndTitle *** 
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; 

}

14. There are other ways to find controls, such as using the returnObjById(id) function, but for whatever reason, Microsoft doesn’t recommend using this approach. On the other hand, in the SharePoint Community the getTagFromIdentifierAndTitle function is well known, well documented, and heavily used, so I recommend starting with this method whenever possible.

I hope that helps!

Tom Molskow








20 comments:

Jonathan said...

I tried to use this to hide and reveal a drop down list depending upon the choice from a prior drop down list (i.e. cascading drop downs).

I edited the code based on my fields and inserted into the content editor web part, but now on the form I just see the code at the top and the hide doesn't work.

Any suggestions? Thanks!

Tom Molskow said...

Hey Jonathan,

If you can actually see the code in the Content Editor Web Part then that means you didn't add it in the Source Editor but instead in the Rich Text Editor. Re-open your CEWP, remove the code from the Rich Text Editor, add it back in the Source Editor, save, refresh and retest.

I hope that helps!

Tom

Lauri_v said...

Hello Tom,

I couldn't get the code working. First I created a custom list called "Test" with two columns "Task Status" and "Reassignment Reason" Then I added the CEWP to my ediform.aspx and pasted the code, but it seems to do nothing. Can you help me, please?

cheers
- Lauri, Finland

p.s. Jonathan forgot the script tags.

Tom Molskow said...

Hey Laurie,

To debug add alerts to the code, for example:

var theInputMLTRR = getTagFromIdentifierAndTitle("TextArea","TextField","Reassignment Reason");
alert("theInputMLTRR : " + theInputMLTRR);

//*** Hide the Field ***
function hideField()
{
theInputMLTRR. parentNode.parentNode.parentNode.style.display = "none";
alert("hideField ran");
}
//*** Reveal the Field ***
function revealField()
{
theInputMLTRR .parentNode.parentNode.parentNode.style.display = "";
alert("revealField ran");
}

Please try that and LMK what you find. Also - what types of fields did you add? "Task Status" should be a choice and "Reassignment Reason" should be a multiline. Finally, be sure you are using the exact field name in the getTagFromIdentifierAndTitle method.

I hope that helps!

Tom

Harry Bath-Barranco said...

Hey Tom,

I have been trying to get this to work for the past few days but to no avail.

I have tried just copying the last code (and editing to fit my form), and it didn't work. Following that I tried it removing parts of the functionality to see where it was "falling down".

If I exclude the following:-

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

var theChoice = getTagFromIdentifierAndTitle("TextArea","TextField","Reassignment Reason");
getTagFromIdentifierAndTitle("TextArea","TextField","Reassignment Reason").onchange = function(){revealHideControl()};

//*** Reveal the Field ***
function revealHideControl(){
if (theChoice.value == “Reassign”) {
revealField();
}else
}
hideField();
}
}

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

The field I wan't hidden works correctly, however as soon as I add the above code (and modify it to suite my form), the field stops being hidden. This is despite the drop down option I have chosen to reveal the hidden field NOT being selected.

Any ideas where this might be going wrong?

Thanks,
Harry

Harry Bath-Barranco said...

Hey Tom,

I have been trying to get this to work for the past few days but to no avail.

I have tried just copying the last code (and editing to fit my form), and it didn't work. Following that I tried it removing parts of the functionality to see where it was "falling down".

If I exclude the following:-

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

var theChoice = getTagFromIdentifierAndTitle("TextArea","TextField","Reassignment Reason");
getTagFromIdentifierAndTitle("TextArea","TextField","Reassignment Reason").onchange = function(){revealHideControl()};

//*** Reveal the Field ***
function revealHideControl(){
if (theChoice.value == “Reassign”) {
revealField();
}else
}
hideField();
}
}

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

The field I wan't hidden works correctly, however as soon as I add the above code (and modify it to suite my form), the field stops being hidden. This is despite the drop down option I have chosen to reveal the hidden field NOT being selected.

Any ideas where this might be going wrong?

Thanks,
Harry

Tom Molskow said...

Hey Harry,

I'm sorry you are having problems. Can you capture the value of theChoice field at run time and then post that and any relevant portions of your code so I can take a closer look at the issue?

Thanks!

Tom

Ahmed M. Gamil said...

Hi Tom. Your code unfortunately didn't work for me. I believe it's because the FormFields in SP2010 is different from its counterpart in SP2007. For Example, In 2007 an ordinary SingleLineText field is put in HTML as <Input .. but in PS2010 it's something like <SharePoint:FormField .. and your code can't get that element by it's tag name.

Tom Molskow said...

Hey Ahmed,

I have not had the opportunity to try this code out in SPS 2010, but I'm sure your comment is correct. If you find a modification that works for you LMK and I will post it here and credit you.

Thanks!

Tom

Anonymous said...

Is this problem as simple as a typo in bracketing? In function revealHideControl, I see two open brackets and four closed. Shouldn't the closing bracket after the "else" be an opening bracket?

Tom Molskow said...

Hello,

Excellent catch! I have corrected that typo in both locations.

Thanks!

Tom

Unknown said...

Does anyone find a solution for Sharepoint 2010?

Thanks!
Clement

Tom Molskow said...

Hello,

Sorry for the late reply. I will try to make this work in SPS 2010 and LYK what I find.

Thanks!

Tom

Teddybeardog said...

Hi Tom:

What was the resolution for Harry's problem here? I'm having the same problem. I have added alerts but I'm not getting any.

Tom Molskow said...

Hey Teddybeardog,

I asked Harry to capture the value of the Choice field(s) at run time and then post that and any relevant portions of his code so I could take a closer look at the issue, but he never got back to me. Can you try that and then post the information back to my blog?

Thanks!

Tom

Anonymous said...

So, does it work in SP 2010?

Tom Molskow said...

To Anonymous,

I'm really not sure, want to try it?

Tom

Anonymous said...

Hi Tom,

Can we accomplish the above code in DispForm? and is it compatible with SP2010?

Thanks

Tom Molskow said...

Hello,

Can we accomplish the above code in DispForm?

Since the display form does not allow input, I don't see a way to trigger the hide/reveal.

and is it compatible with SP2010?

I'm not sure, I have not tried it because in a SP 2010 list you can now use Infopath to create advanced list forms and obviously this is a much better way to go.

Thanks!

Tom

Unknown said...

For everone who is having problems getting this to work, the code attempts to get theInputMLTRR before the page was finished loading. moving "var theInputMLTRR = getTagFromIdentifierAndTitle("TextArea","TextField","Reassignment Reason");" into the hideField function enabled this to work on sharepoint 2007.


Change

_spBodyOnLoadFunctionNames.push("hideField"); {
var theInputMLTRR = getTagFromIdentifierAndTitle("TextArea","TextField","Reassignment Reason");
//*** Hide the Field ***
function hideField()
{
theInputMLTRR. parentNode.parentNode.parentNode.style.display = "none";
}


To

_spBodyOnLoadFunctionNames.push("hideField"); {
//*** Hide the Field ***
function hideField()
{
var theInputMLTRR = getTagFromIdentifierAndTitle("TextArea","TextField","Reassignment Reason");
theInputMLTRR. parentNode.parentNode.parentNode.style.display = "none";
}