Monday, July 25, 2011

How to Get SharePoint ASP.NET Auto Generated Control ID Using JavaScript

One of the most irking problems I have encountered while working with ASP.NET are auto-generated server control IDs.  My particular issue was figuring out how to gain a handle on the Hour and Minute fields in the DateTime object shown below

SharePoint's version of the DateTimePicker

Everytime a client loads the page, the server generates its own ID for the Hour and Minute elements.

HTML for the Hour dropdown
HTML for the Minute dropdown

As you can see in the screenshots above, ASP.NET mauled the client-side IDs with "ct100........."

Google searching yielded one possible solution: <%=#YourControlID.ClientID%>.  I tried this and got "An error occurred during the processing of Page.aspx.  Code blocks are not allowed in this file."  This error meant that my SharePoint environment was configured to stop any server-side code from being executed on the client-side.  Asking my SharePoint administrator to relax the security settings would be pretty stupid so it was not an option.

After five additional hours of futile Google searching, I got lucky and found this post on Marc Anderson's blog.  Although it was not a direct solution, it was something I could work with.  I modified the function to return the control's client-side generated ID and used it with jQuery to gain a handle on the Hour and Minute fields.

$(document).ready(function() {
  // Get the control IDs of the DateTimePicker dropdowns
  var startHourID = getTimeID('ff3_1', 'DateTimeFieldDateHours');
  var startMinuteID = getTimeID('ff3_1', 'DateTimeFieldDateMinutes');
  
  // Get the hour and minute value from their IDs using jQuery
  var startHour = $("[id='" + startHourID + "'] :selected").text();
  var startMinute = $("[id='" + startMinuteID + "'] :selected").text();
 
  // Display the hours and minutes
  alert("Hour: " + startHour);
  alert("Minute: " + startMinute);
});

/** Get the client-side ID of the Hours or Minutes control in the DateTimePicker field.
 *  @param fieldID    The control's ID before being mauled client-side
 *  @param fieldType  Use DateTimeFieldDateHours or DateTimeFieldDateMinutes
 *  @return  The client-side ID
 */
function getTimeID(fieldID, fieldType) {
  // Get all dropdown elements in the page
  var tags = document.getElementsByTagName('select');
  var controlID;
  for (var i = 0; i < tags.length; i++) {
    // alert(' tags[' + i + '].id=' + tags[i].id);
    // Find the element with the matching fieldID and fieldType
    if (tags[i].id.indexOf(fieldID) > 0 && tags[i].id.indexOf(fieldType) > 0) {
      controlID = tags[i].id;
    }
  }
  return controlID;
}

To get the control's client-side generated ID, simply call getTimeID with the appropriate parameters.  The caveat here is that fieldID and fieldType must always be present in the generated ID ctl00_PlaceHolderMain_g_dcc91698_d7a9_43a3_baf2_91d2ae764f94_ff3_1_ctl00_ctl00_DateTimeField_DateTimeFieldDateHours.  This function will not work if a completely random ID is generated each time the page is loaded because there will be nothing static for you to latch onto.

To test whether I hooked on correctly to the Hour and Minute fields, I alerted their values.


I hope this saves many people hours of anguish.  Happy coding!