Skip to main content Home Help (new window) Eric Shupps
Go Search
Home
Blogs
Company
Products
Services
Current News
Idera Acquires Sonar from BinaryWave
BinaryWave Announces SharePoint Performance Optimization Service
Upcoming Events
Home > Blogs > Eric Shupps > Posts > JavaScript, SharePoint, and the getElementById Blues
JavaScript, SharePoint, and the getElementById Blues
It doesn't take long for anyone who does client-side coding in SharePoint to figure out that the trusty ol' getElementById() method just ain't all it's cracked up to be.  Sure, it works fine in standard ASP.NET pages but in SharePoint all that pretty client-side code goes right out the window.  Just what is going on here?
 
The simple answer is that SharePoint is coming between you and your control ID's.  Keep in mind that a typical SharePoint page may have dozens of individual server controls, user controls, field elements web parts, and other objects scattered throughout the page hierarchy.  In order to maintain viewstate for all these elements, SharePoint must translate simple, easy-to-read ID's into something that it can be sure is unique, as it has no way to determine if that same control ID might exist somewhere else on the page.  So something as easy as 'txtTextBox1' becomes 'ctl00$m$g_1438a021_e6f0_4010_bf4b_33713d2e724a$ctl00
$PersProviderGeneral.ascx$SubNavBase1$General$fvFormView$txtTextBox1'.  Ouch. 
 
The real problem here is that SharePoint's funky ID's aren't created until the page is rendered and they may change depending upon what other elements exist on the page.  So just grabbing the ID from View Source doesn't guarantee that your script is going to work.  The trick here is to capture the ID before it is rendered to the client and use it in your getElementById() method.
 
Instead of this:
 
document.getElementById('txtTextBox1');
 
You'll need to do this:
 
document.getElementById('<%=txtTextBox1.ClientID%>'); 
 
But wait, that's only the beginning.  If you, like most other ASP.NET 2.0 programmers, are using any .NET-specific controls, such as GridView, FormView, ItemTemplate, etc. you've got another problem.  SharePoint builds the unique identifier for individual controls by inspecting the control hierarchy; that is, the long ID string is actually composed of strings representing the control AND it's parent elements.  So the sample ID above actuall represents this structure:
 
[General Control ID]$[Page GUID]$[Root User Control Name]$[Container Control Name]$[Container Control Name]$[Parent Control]$[Child Control]
 
This will come back to haunt you if your contol is inside of another control as [Control Name].ClientID will only generate an ID with the topmost parent (the page itself) and the specific control name - it will skip the containing elements in between.  To get around this, you frst need to locate the control in the page hierarchy using server-side script and then get the client ID.  So, if you are trying to reference a textbox inside of a FormView, the script would look like this:
 
document.getElementById('<%= ((TextBox)this.fvFormView.FindControl("txtTextBox1")).ClientID %>')
 
The above code uses the FindControl method to locate a control with the ID of 'txtTextBox1' inside of a Form View with an ID of 'fvFormView', casts it as a System.Web.UI.WebControls.TextBox object, then renders the Client ID property for the control in its proper context.  Now the client-side script will have the proper ID string to located the control on the page after SharePoint has intervened.  This same method can be used for just about any control on the page so long as you remember to honor the hierarchy of the control structure (including nested controls). 

Comments

It is not sharepoint, it is Asp.Net

Most of the controls in sharepoint implement INamingContainer interface which essentially ensures the uniqueness of ID of the control no matter how it is used.  This is an Asp.Net concept and is not something that sharepoint is not a sharepoint only thing. Typically if your control needs to do something in script and is rendering the startup script or atleast rendering the call to that script the best way is to pass the ClientID in the call to that script. The value of ClientID can be obtained in the code behind and passed in when rendering the call to your script. The example below explains basically how to do it. The only gotcha is that the clientId value is only available after the control is added to the control collection.

For e.g
//Script
SomeSriptMethod(Id)
{
   var ctrl = document.getElementById(Id);
  //Do something with the control
}

//Html - Say this script is called by onClick handler on an "a" tag

<a onClick="javascript:SomeScriptMethod('ClientIdFromCodeBehind') href="">aaa</a>

Now the next thing is when your control is adding the hyperlink the code should kind of look like this

CreateChildControls(...)
{
    HyperLink link = new HyperLink();
    //Set  properties on the link as needed
   this.Controls.Add(link);
   //Note the clientId for link wont have the correct value till you add it to the control collection otherwise it will give you what you set in the Id for the link
   link.Attribute["onClick"] = "javascript:SomeScriptMethod(' + link.ClientID + "');" ;
   
}

Note: I am not doing any encoding but the control should do appropriate encoding of link.ClientID and this code wont compile and should be treated as pseudo code only.
at 8/9/2007 1:02 PM

Getting the ID

Not sure I followed the 2nd post here, above.  How can you pass in and retrieve an ID using

var ctrl = document.getElementById(Id);

when you don't even know the ID in the first place because it's being made unique when rendered by SharePoint each time?  Wasn't that the whole point of this - to get an ID back for the control when you didn't know what the ID is, based on some other property the control has?

This would work if you use the "title" property on an input control, normally.....

function getTagFromTitle(tagName, title) {

// tagName = "input"
// title = the title given to the control

  var tags = document.getElementsByTagName(tagName);

  for (var i=1; i < tags.length; i++) {
    var tempString = tags[i].name;
    if (tags[i].title == title) {
      return tempString;
    }
  }
  return 'null';
}

The problem is that this kind of thing doesn't seem to work in SharePoint, at least for me, for bringing back anything.  I've tried

var tempString = tags[i].id;

and

var tempString = tags[i].name;

in that function above, so far, while passing in the title "Search Box" for the SearchCenter template to try and give me the ID or name for the search box, so I can get its .value and pass on the keywords.  Can't get anything out of it - searchTerm is null in the function below.  This script does work when used in VB 2005 against a regular, common, HTML input textbox control, however:

function getSearchTerm() {

var searchBoxElem = getTagFromTitle("input", "Search Box");
var searchTerm = document.myForm.elements[searchBoxElem].value;
alert(searchTerm);
}

When trying to use

document.getElementById('<%= ((TextBox)this.fvFormView.FindControl("Search Box")).ClientID %>')

I get the error:
 
An error occurred during the processing of /tsearch/default.aspx. Code blocks are not allowed in this file. 

Even commenting that code out didn't correct the error - had to delete that line altogether before I got my SearchCenter back up.

So what gives?  How are we supposed to get the values out of SharePoint controls?
at 2/19/2009 12:48 PM

Thanks

Thanks code worked for me
at 4/17/2009 12:53 AM

This is how I reference an element via JS in SP...

function getMyElement(sName) {
try {
var aTagTypes = new Array("DIV", "INPUT");
sName = sName.toUpperCase();
for (var i = 0; i < aTagTypes.length; i++) {
var sTagType = aTagTypes[i].toString().toUpperCase();
var aEmts = document.getElementsByTagName(sTagType);
for (var ii = 0; ii < aEmts.length; ii++) {
var oOb = aEmts[ii];
var sID = oOb.getAttribute("id").toString().toUpperCase();
if (sID.indexOf(sName) > -1) {
return oOb;
}
}
}
} catch (e) {
alert("ERROR: " + e.Description);
}
return null;
}
 
function doThis() {
var s = getMyElement("Text1").value;
//alert("The value of this field is: " + s);
getMyElement("oDIV_02").innerHTML = s;
}
at 11/20/2009 2:43 PM

Trying to insert table rows into an sharepoint editform using Javascript

We want to add header breaks between editform input boxes based on strings in the column names. We are very close, but the insertbefore line does not execute.

The full post in under Technet Sharepoint - "Inserting a Table row with Javascript" user JCNET

<script type="text/javascript">
var theRows = document.getElementsByTagName("TR");
var r = 0;
var strTitle = "";
while (r < theRows.length)
{ try
{ strTitle = theRows[r].innerText || theRows[r].textContent;
strTitle = strTitle.replace(/\n|\r|\t|\^ /g,"");
var row = theRows[r],
cells = row.getElementsByTagName('td');
if (cells[0].className.indexOf('ms-formlabel') > -1) 
{
if (strTitle.indexOf("(HP)") == -1)
{
  theRows[r].style.display = "none";
}
 else
 {

 theRows[r].cells[0].innerHTML = theRows[r].cells[0].innerHTML.replace("(HP)","");
 
 if(/H\:/.test(strTitle))
      {
        var fheader = (strTitle.match(/\(H\:(.*?)\)/g));
        //var header = fheader.replace("(H:","").replace(")","");
        var header = fheader;
newrow=document.createElement('tr');
newcell=document.createElement('td');
newcell.appendChild(document.createTextNode(header));
newrow.appendChild(newcell);
        alert(header);
        r.parentNode.insertBefore(newrow,r);
        alert("Done");
}
 }
}

}catch(err){}r+=1;
}
</script>
at 12/8/2009 4:17 PM

Re: JavaScript, SharePoint, and the getElementById Blues

or just explicitly set the id of the control in your code and the client-side code will work as expected:

txtTextBox1.ID = "txtTextBox1";

From then on:
document.getElementById('<%=txtTextBox1.ClientID%>');
should work properly in your client-side code
at 1/17/2010 2:43 AM

Add Comment

Items on this list require content approval. Your submission will not appear in public views until approved by someone with proper rights. More information on content approval.

Title


Body *


Your Name


Your URL


Comment Date *

To prevent spam from automated bots please provide a valid date in the format "MM/DD/YYYY".
Attachments