Feeds:
Posts
Comments

Archive for July, 2011

I really don’t like having to work with the ClientId of page elements in ASP.Net. You know, you give a textbox an ID of, say, “myTextbox” and then try to get a reference to it client side in Javascript and it fails. You try (with jQuery, say) to run:

$('#myTextbox').attr('value', 'BLAH!')

and it returns null. You inspect your generated html and find that your textbox has an ID of something like: ctl00_m_g_3bd415ee_814a_46e1_a0f1_a2cf8227bea0_ctl00_myTextbox

I understand why Microsoft molests the IDs that I assign to it – it’s making sure that (as dictated by W3c) IDs of elements on my page are unique, and it does this by assigning a GUID to my webpart, and then appending to it with the details and IDs of my individual controls.

But I want to (relatively easily) get a reference to the webpart GUID so that, in my webparts, I can manipulate my DOM elements client side (in Javascript).

So what I do (glad to hear if there are better approaches!) is:

1. Create and Implement an Interface to Expose the ClientId

I create an interface for my Visual Web Parts called IVisualWebPart that my User Controls implement. It looks (so far) like:

using System.Web.UI.WebControls.WebParts;

namespace MyNamespace.Interfaces
{
public interface IVisualWebPart
  {
    WebPartManager WebPartManager { get; set; }
    string ClientId { get; set; }
  }
}

I don’t actually use the WebPartManager in this example, but I use it in other cases, so I’ve just left it in here.

And then in the usercontrol itself:

#region IVisualWebPart members

WebPartManager webPartManager { get; set; }
public WebPartManager WebPartManager
{
get
{
if (webPartManager == null)
throw new NullReferenceException("The instantiating web part must assign WebPartManager to this UserControl.");

return webPartManager;
}
set
{
webPartManager = value;
}
}

string clientId { get; set; }
public string ClientId
{
get
{
if (clientId == null)
throw new NullReferenceException("The instantiating web part must assign ClientId to this UserControl.");

return clientId;
}
set
{
clientId = value;
}
}

#endregion

And in the WebPart code (when you create a Visual WebPart in Sharepoint, it generates a WebPart as well as a UserControl with code behind, and sets the WebPart to fetch and display the UserControl):

protected override void CreateChildControls()
{
Control control = Page.LoadControl(_ascxPath);
(control as IVisualWebPart).WebPartManager = this.WebPartManager;
(control as IVisualWebPart).ClientId = this.ClientID;
Controls.Add(control);
}

2. Expose the ClientId via Code

I can then expose the ID on the page by injecting some JS onto the page from code behind like this:

private void AddClientIdJs()
{
StringBuilder js = new StringBuilder();
js.Append("<script type='text/javascript'>");
js.Append("$(function () {");
js.Append("var thisClientId = \"" + this.clientId + "\";");
js.Append("DispForm_Committee_RelatedAppointmentsUserControl_startUp(thisClientId);");
js.Append("});");
js.Append("</script>");
this.Page.Header.Controls.Add(new LiteralControl(js.ToString()));
}

I call this method from an overridden “CreateChildControls()”.

You’ll note that I’m actually using the Client ID in a call to *another* javascript file (myUserControl_startUp(thisClientId)). I could just as easily assign the ClientId to a variable and use it on the page, but I like to instead keep my Javascript external to the page as much as possible and instantiate it this way. It lets me more easily reuse functions across pages, and just feels like a cleaner separation of concerns.

3. Reference your elements

And finally, in that external JS, you can now get at your elements with jQuery and via code like the following:

function myUserControl_startUp(thisClientId) {
  //alert('thisClientId: ' + thisClientId);
  var selectedTabIdx = $('#' + thisClientId + '_ctl00_hiddenTabIdx').val();
}
Advertisements

Read Full Post »