Supporters of End User
Web

Show/Hide Lookup fields with jQuery

Item is currently unrated. Press SHIFT+ENTER to rate this item.1 star selected. Press SHIFT+ENTER to submit. Press TAB to increase rating. Press SHIFT+ESCAPE to leave rating submit mode.2 stars selected. Press SHIFT+ENTER to submit. Press TAB to increase rating. Press SHIFT+TAB to decrease rating. Press SHIFT+ESCAPE to leave rating submit mode.3 stars selected. Press SHIFT+ENTER to submit. Press TAB to increase rating. Press SHIFT+TAB to decrease rating. Press SHIFT+ESCAPE to leave rating submit mode.4 stars selected. Press SHIFT+ENTER to submit. Press TAB to increase rating. Press SHIFT+TAB to decrease rating. Press SHIFT+ESCAPE to leave rating submit mode.5 stars selected. Press SHIFT+ENTER to submit. Press SHIFT+TAB to decrease rating. Press SHIFT+ESCAPE to leave rating submit mode.
Categories:MOSS; WSS; 2007; 2010; SharePoint Designer; Javascript and jQuery; Site Manager/Power User

 

In this article, I will show you how to show and hide form fields dependent on the value of a drop-down list field, with a special look at what to do with Lookup fields. I am often given requirements for SharePoint forms that have functionality that isn’t possible with the out-of-the-box controls, this is one such example.

2010-12-15-ShowHideLookUpFields-01.png

The New Form looks like this:

2010-12-15-ShowHideLookUpFields-02.png

Field SelectA contains values “item 1”, “item 2” and so on. Field SelectB contains values “item a”, “item b” etc. as shown above.

What I need is to only show field SelectA when the value of MasterSelect is “Select A”, and to only show the field SelectB when the value of MasterSelect is “Select B”.

For the purpose of this example, I am using the standard custom list form that SharePoint Designer builds. Fields SelectA and SelectB are found in separate rows of a table:

<tr>
	<td width="190px" valign="top" class="ms-formlabel">
		<H3 class="ms-standardheader">
			<nobr>SelectA</nobr>
		</H3>
	</td>
	<td width="400px" valign="top" class="ms-formbody">
		<SharePoint:FormField runat="server" id="ff3{$Pos}" ControlMode="New" FieldName="SelectA" __designer:bind="{ddwrt:DataBind('i',concat('ff3',$Pos),'Value','ValueChanged','ID',ddwrt:EscapeDelims(string(@ID)),'@SelectA')}"/>
		<SharePoint:FieldDescription runat="server" id="ff3description{$Pos}" FieldName="SelectA" ControlMode="New"/>
	</td>
</tr>
<tr>
	<td width="190px" valign="top" class="ms-formlabel">
		<H3 class="ms-standardheader">
			<nobr>SelectB</nobr>
		</H3>
	</td>
	<td width="400px" valign="top" class="ms-formbody">
		<SharePoint:FormField runat="server" id="ff4{$Pos}" ControlMode="New" FieldName="SelectB" __designer:bind="{ddwrt:DataBind('i',concat('ff4',$Pos),'Value','ValueChanged','ID',ddwrt:EscapeDelims(string(@ID)),'@SelectB')}"/>
		<SharePoint:FieldDescription runat="server" id="ff4description{$Pos}" FieldName="SelectB" ControlMode="New"/>
	</td>
</tr>

Beneath the custom list form web part, I added a <script> block. I’ve added the jQuery reference here too. This script adds a handler to the change event on the MasterSelect drop-down list:

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
    // add change handler
    $("select[title=MasterSelect]").change(function() {
    	MasterSelectChange();
    });
});

function MasterSelectChange()
{
	var thisVal =  $("select[title=MasterSelect]").val();
	if(thisVal == "Select A")
	{
		// show the SelectA field
		// hide the SelectB field
	}
	else
	{
		// hide the SelectA field
		// show the SelectB field
	}
}
</script>

As it stands, nothing will happen – the next step is to decide how to show/hide the fields. In this simple example, each field to be shown/hidden is within its own table row, so the easiest way is to show/hide the whole row using the <tr> element. I added a class attribute to each <tr> to make them easy to identify:

<tr class="SelectA">
<tr class="SelectB">

The MasterSelectChange() function now looks like this:

function MasterSelectChange()
{
    var thisVal =  $("select[title=MasterSelect]").val();
    if(thisVal == "Select A")
    {
        // show the SelectA row
        $(".SelectA").show();
        // hide the SelectB row
        $(".SelectB").hide();
    }
    else
    {
        // hide the SelectA row
        $(".SelectA").hide();
        // show the SelectB row
        $(".SelectB").show();
    }
}

In order to show/hide the fields correctly when the form is first displayed, I added a call to MasterSelectChange() in the Document Ready section:

$(document).ready(function() {
    // add change handler
    $("select[title=MasterSelect]").change(function() {
        MasterSelectChange();
    });
    // call the change function to set up form for first display:
    MasterSelectChange();
});

The Problem

At first glance, this appears to work just as we want: the form is displayed with only field SelectA shown (as the default value of MasterSelect is “Select A”); changing MasterSelect to “Select B” shows field SelectB and hides SelectA. However, there is some peculiar functionality taking place: the behaviour of the drop down lists is broken. The first one that is pressed works (the list of values is displayed), but if the value of MasterSelect is changed, the field that is now shown will not show its drop-down list.

This is because of the way that SharePoint creates these drop-down list controls (in Internet Explorer only). Lookup fields with fewer than 20 items are shown as “real” drop-down lists (and don’t exhibit this problem); for lookup fields with 20 or more items, the drop-down control is created by the combination of 3 elements:

<input><img><select>

The <input> and <img> are made to look like a “real” drop-down list, and clicking on the <img> displays the lookup values in a list beneath the field, as is shown in the New Form screenshot above.

However, it’s slightly more complicated than that… the HTML page that is first displayed is rendered with only the <input> and <img> elements. The <select> element is created on-the-fly the first time a drop-down image is clicked.

When the <select> is created, when the first drop-down image is clicked, it is placed into the DOM tree directly next to the <img> that was clicked, as shown by this extract from Internet Explorer 8’s Developer Tools:

2010-12-15-ShowHideLookUpFields-03.png

When any lookup field’s drop-down image is clicked, it uses the same <select> element to display the lookup entries – but SharePoint’s JavaScript ensures that the list of values is correct, and that it is positioned beneath the correct <input>.

This means that if we hide the lookup field which has the newly created <select>, all the elements that make up this lookup field are hidden: <input>, <img> and <select>. So when another lookup field’s drop-down image is clicked, the <select> is not shown because it is contained within a hidden element.

The Solution

In order for the <select> to be shown for all lookup fields, it needs to be placed somewhere else in the DOM tree – somewhere that will not be hidden. This is achieved by a two-step approach:

  1. Call the SharePoint function that creates the <select> element
  2. Use jQuery to move the <select> element

The function to call in Step 1 can be found by a little digging, once again using IE8’s Developer Tools. The lookup field’s drop-down <img> has an onclick event that calls a function ShowDropdown(). This function can be found in SharePoint’s core.js file:

function ShowDropdown(textboxId)
{
	var ctrl=document.getElementById(textboxId);
	var str=ctrl.value;
	var opt=EnsureSelectElement(ctrl, ctrl.opt);
	ctrl.match=FilterChoice(opt, ctrl, "", ctrl.value);
	ctrl.focus();
}

This function then calls another function, EnsureSelectElement (also found in core.js):

function EnsureSelectElement(ctrl, strId)
{
	var select=document.getElementById(strId);
	if (select==null)
	{
		select=document.createElement("SELECT");
		ctrl.parentNode.appendChild(select);
		select.outerHTML="<select id=\""+strId+"\" ctrl=\""+ctrl.id+"\" class=\"ms-lookuptypeindropdown\" name=\""+strId+"\" style=\"display:none\" onfocusout=\"OptLoseFocus(this)\"></select>";
		FilterChoice(select, ctrl, ctrl.value, "");
	}
	return document.getElementById(strId);;
}

This function creates the <select> element if it doesn’t exist, so this is the function we need to call in our script. The two parameters are:

  • ctrl: the <input> element
  • strID: the ID to use for the <select> - I have discovered that this is always “_Select”

So now it’s a matter of creating the <select> for one of the lookup fields, using jQuery to find the DOM element for the lookup field SelectA:

EnsureSelectElement($("input[title=SelectA]")[0], "_Select");

Step 2 is to move the <select>. I have chosen to move it beside the MasterSelect drop-down field, which is always shown. This jQuery snippet does just that:

$("select[title=MasterSelect]").parent().append($("#_Select"));

Note that the jQuery function “append” will move an existing DOM node, as explained in the jQuery documentation (http://api.jquery.com/append/).

This code is added into the Document Ready section:

$(document).ready(function() {
    // add change handler
    $("select[title=MasterSelect]").change(function() {
        MasterSelectChange();
    });
    // call the change function to set up form for first display:
    MasterSelectChange();
    // ensure the <select> is created:
    EnsureSelectElement($("input[title=SelectA]")[0], "_Select");
    // and move to an un-hidden location (next to the MasterSelect <select> element):
    $("select[title=MasterSelect]").parent().append($("#_Select"));
});

After this code has been run, the DOM tree looks like this:

2010-12-15-ShowHideLookUpFields-04.png

Comparing this to the DOM tree shown earlier, you can see that the <select> is no longer within the <tr class=”SelectA”> element, but contained with the <tr> above it.

The form now has all the functionality it needed, and all the controls behave correctly. Job done!

I hope this gives you a little insight into what’s happening “beneath the hood” of SharePoint’s lookup fields, and how it’s possible to gently tweak them to do what you want. Note that the behaviour of lookup fields is Internet Explorer only – e.g. Firefox and Chrome always show “real” drop-downs, so this code isn’t needed; however, it won’t break the page in FF or Chrome  if it’s included.

Comments

Guido de croon

Clusterfck?

It must be me but I find this to be a clusterfck of html IDs and other pain. You depend on internal rendering mechanisms that you will simply not be able to support in the long run, rely on "#_Select", HTML literals etc. If this is end user SharePoint, I simply don't want to be an end user.
 
there's a dev for that....
 
sorry, but that is my 3 ct

Posted 16-Dec-2010 by Guido de croon
Alex Lee

Response to Guido

Thanks for your comment. The only parts of this solution that are not under the end-user's control are the parts rendered by SharePoint itself: the lookup controls. For these, we rely on one hard-coded ID value ("_Select"), and one internal SharePoint javascript function (EnsureSelectElement). All the other HTML layout and jQuery is fully under our control.
 
In terms of support in the long run, this is a SharePoint 2007 solution. I have not tried it using SP2010, so can't comment on suitability.
 
Yes, this solution does lean towards being more of a technical solution (more for Power-User than End-User, perhaps), but I have tried to show that it does not require reams of complex code, and as such fits within the reaches of those who cannot write server-side C#, deploy DLLs etc.
 
Alex.

Posted 16-Dec-2010 by Alex Lee
Matthew Bramer

Very nice look under the hood...

I'm glad to see this posted Alex.  This is a commonly asked question on the STP Forums, so it's much appreciated to have an article to reference.
 
Guido does make a good point.  It's probably best to state upfront what the user will have to hard code.  You could simply modify the code to have variables that reference your column names.
 
Besides that one critique, I really enjoyed reading this and look forward to more of your articles!
 
Cheers,
Matt

Posted 17-Dec-2010 by Matthew Bramer
Leo Gershfang

I have achieved item level security with jquery

I also hide and disable fields using jquery but I took it a step further. I list the steps needed to achieve field level permissions. There are many uses for this! Enjoy! http://sharepointneedtoknow.blogspot.com/

Posted 10-Jan-2011 by Leo Gershfang
Paul Ong

Comment Character Counter

Hi Alex, this is a nice post, I do have some query though, for an input box like this of the comment field, when you look under the hood is just a bunch of on the fly html created.. in my case i need to know how can i control or know the number of characters being entered, what i wanted to achieve was that I want to limit the characters entered by a user. Any approach would do.. currently, I'm using jQuery but i can't just wrap the big hound element... thanks in advance

Posted 14-Jan-2011 by Paul Ong
Dave Patel

Simplicity is sometimes best

Too much work. Here is a simple Javascript method...
 
'
function hideOrShowField() {
var selector = getTagFromIdentifierAndTitle("SELECT", "", "YOUR_TITLE");
selector.onchange = fieldsToHideOrShow;
                      
     function fieldsToHideOrShow() {
                         if(selector.value == "Value1"){
                          showThis;
                      }
                         if(selector.value == "Value2"){
                          hideThis;
                      }
                 }
                }
'

Posted 25-Apr-2011 by Dave Patel
raghu

How to hide the Context menus for an Item

Hi Alex,

I am trying to hide the context menus( Workflows, Checkin, CheckOUt) from particular users. I have used the below script for it and it works. But the problem here is I am able to see the script working on my login, where as When some other user login to the page the script doesnot work( I mean they are able to see the context menu drop downs) can you please help me out on this.
 
 
 
<script language="javascript">
function AddCheckinCheckoutMenuItem(m, ctx, url).
{
return;
}
function AddSendSubMenu(m,ctx)
{
return false;
}
function AddWorkflowsMenuItem(m, ctx)
{
return;
}
</Script>

Posted 22-Jun-2011 by raghu
CJSigler

Show/Hide Lookup fields with jQuery - Has anyone tried in SP2010

I an having a hard time figuring out what to insert where. Has anyone tried this solution in SP2010 yet?

Posted 28-Sep-2011 by CJSigler
ni

help please

where I write this code

Posted 24-Mar-2012 by ni
lisaa3

hide unhide field

Thank You MR Alex Lee , it's very interesting post

Posted 06-Apr-2012 by lisaa3
Kishan Srivastava

Thanks a lot Mr. Alex Lee. It help me alot...!! One Issue with it...!!

I am using this Code in SharePoint Edit.aspx Page and it works , but the problem it only hides the control not the row and title. So please if you can help me on that.
Any Help would be appreciated.
Below is the code which i am using....!!
 
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
    // add change handler
    $("input[title='Test Value']").change(function() {
        MasterSelectChange();
    });
    // call the change function to set up form for first display:
    MasterSelectChange();
});
 
function MasterSelectChange()
{
    var thisVal =  $("input[title='Test Value']").val();
    if(thisVal == "AU")
    {
     $("select[title='Test_Status']").hide();
     
      }
    else
    {
      $("select[title='Test_Status']").show();
  
    }
}
</script>

Thanks

Posted 10-May-2012 by Kishan Srivastava
Kishan Srivastava

Thanks a lot Mr. Alex Lee. It help me alot...!! One Issue with it...!!

I am using this Code in SharePoint Edit.aspx Page and it works , but the problem it only hides the control not the row and title. So please if you can help me on that.
Any Help would be appreciated.
Below is the code which i am using....!!
 
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
    // add change handler
    $("input[title='Test Value']").change(function() {
        MasterSelectChange();
    });
    // call the change function to set up form for first display:
    MasterSelectChange();
});
 
function MasterSelectChange()
{
    var thisVal =  $("input[title='Test Value']").val();
    if(thisVal == "AU")
    {
     $("select[title='Test_Status']").hide();
     
      }
    else
    {
      $("select[title='Test_Status']").show();
  
    }
}
</script>

Thanks

Posted 15-May-2012 by Kishan Srivastava
Siyasanga

I've used Dave Patel's approach

I've used Dave Patel's way of doing it and it works. The reason i used it is that my form is not a custom form, the fields are created at runtime only because they're taken from the content type attached to that particular document library. The fields hide/show as requested when a certain option is selected on the dropdown. My problem is that it works well on a normal dropdown but doesn't work at on a complex dropdown(that dropdown created by IE if items are more than 20). How can i get the onchange event to fire on the complex dropdown because it seems as if it's not firing at all?? 

Posted 28-Feb-2013 by Siyasanga
LA

Dave Patel's Approach

Where do you insert the code and what part of the code do you change?
Thanks

Posted 28-May-2013 by LA
Mike Mathews

Help on Hiding Four Fields

I have a list of status' and I need to hide four fields until the ticket status (which is a dropdown) equals redirect, cancelled, or complete. the fields that need to be hidden are:
1-Dropdown
1-Radio Button section
2-Date Fields
 
Could someone show me how this can be done?

Posted 30-Jul-2013 by Mike Mathews

Notify me of comments to this article

E-mail:
   

Add Comment

Title:

 
Comment:
Email:

   


Name:

 
Url: