SharePoint Lookup field: how does it work and how to add JavaScript event handler function to it?
Due to a lot of comments and questions to my last year’s post about Attaching functions to SharePoint form fields concerning especially lookup fields on which the demo was made, I’ve decided to take a deeper dive into SharePoint’s Lookup Field and how to manipulate it client-side, since it behaves different in different situations. On the image below you can see two lookup fields – rendered different.
Even though new SharePoint is about to go public beta I’ll still show how to handle this in SharePoint 3.0 or 2007
How does it work?
Before explaining how to attach a functon or event handler to a SharePoint lookup field let’s take a look on how SharePoint lookup field is rendered in HTML and which is its behavior – considering client-side.
Lookup to a list with less than 20 items:
If your lookup field is reading from a list that has 19 or less items, the lookup field is rendered like a normal HTML dropdown field (HTML <SELECT> tag). The options in the select tag present possible choices. The text of the option is the lookup value, the value of the option is the lookup ID which SharePoint uses to properly link to the item.
The select has a title that equals the field display name, so you can easily use the getField function that is published here. So you can also easily bind an “onchange” event to it.
Lookup to a list with 20 or more items
When a list that the lookup field is reading from a list with 20 and more items, the story becomes more complicated. But only in IE. In FireFox and other browsers the lookup field with 20+ items still gets rendered as a SELECT element. In IE the story starts:
When a Lookup field has 20+ items in IE it gets rendered as a simulation of a combo box (SELECT). It is rendered as an INPUT text box with an image beside. The reason for this is to enable “auto suggest”/filtering feature as you type values in the INPUT textbox.
The image next to input element is pretty straightfoward. It has an “onclick” event that triggers the select.
The input field on the other hand has a lot of event handlers bound to it (keypress, keydown, keyup, etc. shown in the screenshot from IE Developer Tools below) that enable the combo box simulation. The input field also has a “Title” attribute that has a value of the field display name.
One of the attributes of the input field is also choices which contains all the ids and values of the lookup separated with the “|” character.
The first time you press a key or click the image next to the input field, a special function creates a SELECT element and positions it under the INPUT element. Each additional keypress when typing into the input field (typing in the lookup value) functions already attached to the input re-create the input with filtered values. The generated SELECT’s ID is determined with an attribute “opt” on the Input field.
The problem on DOM
This DOM presents an issue to attach an “onchange” event to it since the input field already has so many onkeyup, onkeydown, onkeypress,… events. And since the Select element is generated on the fly it doesn’t exist when the page is rendered and there is only one SELECT element for all the lookup fields with 20+ items in the page. So we can’t attach an event handler to it. At least not easily.
How to attach an event handler to a lookup field?
The good news is that the re IS a way to add a function to trigger when the lookup field value has changed. The input field has another attribute – “optHid” which reveals the ID of a hidden input field that contains the selected lookup ID. That on the other hand is free of any event handlers and we can abuse it.
Since we won’t be typing into a hidden field we can’t add an “onkeyup” or “onkeypress” event to it. But we can add an “onpropertychange” event to it. I’ve read somewhere that this is working only in IE, but that’s ok since we are modifying the behavior for IE. Because the hidden field doesn’t have the title attribute we need to refference it indirectly through the input:
document.getElementById(getField('input','[field_display_name']').optHid)
Enough theory – let’s make a practical example
Let’s make a simple example. When you change a lookup field its ID and text should be coppied to another text field.
Because the SharePoint field can be rendered in two different ways we need to predict both. What we will need first is slightly modified function getField.
function getField(fieldType,fieldTitle) { var docTags = document.getElementsByTagName(fieldType); for (var i=0; i < docTags.length; i++) { if (docTags[i].title == fieldTitle) { return docTags[i]; } } return false; }
The modification is in bold. What this change does is that the function returns false if it can’t find the specified element. Like that we can use it to specify if the field is INPUT (with 20+ items) or SELECT (with 19- items).
function copyLookupIdAndTxt() {
if(getField('select','20+ Lookup'))
{
//if lookup has 19 or less items - SELECT
lookupField = getField('select','20+ Lookup');
lookupSelectedItem = lookupField.options[lookupField.selectedIndex];
getField('input','Title').value = lookupSelectedItem.value + "-" + lookupSelectedItem.text;
}
else
{
//if it has 20 or more items - INPUT
lookupFieldText = getField('input','20+ Lookup');
lookupFieldId = document.getElementById(lookupFieldText.optHid);
getField('input','Title').value = lookupFieldId.value + "-"+lookupFieldText.value;
}
}
Next we create a function that will attach the created function to the lookup field (select or hidden input)
function addHandler() {
if(getField('select','20+ Lookup'))
{
getField('select','20+ Lookup').onchange = function() { copyLookupIdAndTxt() } } else { document.getElementById(getField('input','20+ Lookup').optHid).onpropertychange = function() { copyLookupIdAndTxt() } } }
and finally to make sure the handler gets added let’s add this to the spbodyonloadfunctionnames array
_spBodyOnLoadFunctionNames.push('addHandler');
and the function is adapted to SharePoint’s lookup field.
To recap: the entire code is as follows:
<script type="text/javascript">
function getField(fieldType,fieldTitle) {
var docTags = document.getElementsByTagName(fieldType);
for (var i=0; i < docTags.length; i++) {
if (docTags[i].title == fieldTitle) {
return docTags[i];
}
}
return false;
}
function copyLookupIdAndTxt() {
if(getField('select','20+ Lookup'))
{
//if lookup has 19 or less items - SELECT
lookupField = getField('select','20+ Lookup');
lookupSelectedItem = lookupField.options[lookupField.selectedIndex];
getField('input','Title').value = lookupSelectedItem.value + "-" + lookupSelectedItem.text;
}
else
{
//if it has 20 or more items - INPUT
lookupFieldText = getField('input','20+ Lookup');
lookupFieldId = document.getElementById(lookupFieldText.optHid);
getField('input','Title').value = lookupFieldId.value + "-"+lookupFieldText.value;
}
}
function addHandler() {
if(getField('select','20+ Lookup'))
{
getField('select','20+ Lookup').onchange = function() { copyLookupIdAndTxt() }
}
else
{
document.getElementById(getField('input','20+ Lookup').optHid).onpropertychange = function() { copyLookupIdAndTxt() }
}
}
_spBodyOnLoadFunctionNames.push('addHandler');
</script>



Thanks Boris, your blog is the best of sharepoint cutomizations… you have anything about caml querys??
i have trouble on this.
thanks in advance.
Hello, Erick! Thanks for those kind words. I usually build CAML queries with U2U CAML Builder tool. You can find info about it on http://www.u2u.info/Blogs/Patrick/Lists/Posts/Post.aspx?ID=1315
and download it here: http://www.u2u.be/Res/Tools/CamlQueryBuilder.aspx
Hi, Borris!!
Thanks this solves my problem!!!
What about Lookup with Filtered Values?
This is an option on field types
Hi, Eddie! This is a topic for one of my next articles.
Hi,
Very nice post.
I am trying to do something similar for lookup field and textbox.
I am trying to fire an event when user enters value in textbox and comparing it all values in lookup field.
If value entered by user exists in lookup field then a message will be thrown. “Value already exists”.
I am using the document.getElementId(lookupfield.optHid);
but it does not take care of all the values in lookup field.
Could you please suggest me what i might be doing wrong?
Any help is appreciated.
-Thanks.
Hi. If you’re comparing from text field, you don’t need to bother with attaching an event to lookup. You’d need to attacht the event to the text field (described in http://www.sharepointboris.net/2008/04/add-functions-and-events-to-sharepoint-form-fields/ – but you can use the function on a text field). What you can do is to parse the lookup field’s “choices” attribute or options (if lookup has less than 20 items).
I have an issue with doing batch updates via the webservice in MOSS 2007 with Lookup field with more than 19 values in that lookup list. I am trying to update a list that has a column that is a lookup field (has more than 20 records) when I pass the value this specific field fails. HOwever when I reduce that underlying lookup list to 19 records I am able to update the other list no problem. ???
Ignore my last post, the issue was resolved after recreating the site column and look up field. Had to scrub the data in that field to not include special character!
hi,
I need to add a separate column for attachments saying(account map), i have a requirement where the attachment should be the mandatory field. I have converted the custom list into data view & done certain modification for the same but cannot achieve the required result as i am facing lot of problems with it. Can u suggest me some solution for ths.
Thanx,
Alpa
@Alpa: I’m not sure I understand the problem. If you’re trying to surface attachments to a field it’s needed to be done with a custom event receiver.
Hi ,
Is there a way to copy the value selected into a lookup column, into another column ( maybe hidden)( on the same row)? I can’t find a way to use the value selected in a lookup column…
SharePoint Designer team blog has a post on how to manipulate a lookup field:
http://blogs.msdn.com/sharepointdesigner/archive/2007/06/13/using-javascript-to-manipulate-a-list-form-field.aspx
Hi,
i would like to offer tutorial on how to create basic sharepoint lookup field within visual studio. here is a tutorial with screenshots and comments. it could help to someone.
http://sharepoint-anthony.blogspot.com – Sharepoint Lookup Field
Useful. Thank you for sharing. I see you’re starting a new blog. Great job.
Hi Boris,
I like this article. Quick ? about Lookup field
We have sharepoint designer workflows and custom forms referencing a lookup field. Any ideas on how to change the lookup field to single line of text without having to rework the workflows and custom forms?
Hermano. Excelente este artículo. Muy bacana la información de tu página!
Hi…
Thanks for an interesting article. By the way, is it possible to create a lookup field of a column in another web? The two lists are in different subwebs in my site. The GUI only suggests lists in the same location as the targetlist.
Thanks in advance/Jesper Wilfing
i would like to set the value of a lookup field base on a selected value from another field. is it possible? any idea how?
thanks!