Nov
17
2006
ASP.NET name mangling problem with JavaScript
Posted by admin under
ASP.NET articles
One "problem" with ASP.NET is the automatic generation of names for form variables. Sure it is convinient - and more or less a must when it comes to templated databound server controls to be able to separate the different client side controls. And it works beatifully as long as you just stay on the serverside. Cause after a postback the correct serverside control will be filled with the correct corresponding client controls data - it's so slick some people might not even know that their control with id ddlCategories in the browser is actually called something like _ctl0__ctl2_ddlCategories.
Anyway, when it comes to Javascript crafting you often need to know the id of the control you are supposed to work with. Writing code like this (JQuery syntax)
alert( $('#ddlCategories') ).val() );
will of course not work - since the control actually has an id of _ctl0__ctl2_ddlCategories.
And even more - as soon as you restructure your site you might risk to have it named:
_ctl1__ctl5_ddlCategories or whatever instead, so hardcoding your javascript is not a good solution.
Generating the javascript string from your serveside (asp.net) code might be ok - replacing calls to ddlCategories to ddlCategories.Client ID does the trick but I often like to write at least some code in my ASPX pages.
So meet my little helper:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace JQueryASPNET
{
[DefaultProperty("Text")]
[ToolboxData("<{0}:ASPNETJSNameHandler runat=server></{0}:ASPNETJSNameHandler>")]
public class ASPNETJSNameHandler : WebControl
{
System.Text.StringBuilder oBuilder = new StringBuilder();
public void AddControl(Control c)
{
oBuilder.AppendFormat( " if ( sName == '{0}' ) return '{1}';" + Environment.NewLine, c.ID, c.ClientID );
}
protected override void RenderContents(HtmlTextWriter output)
{
output.Write("<script type=\"text/javascript\"> " + Environment.NewLine);
output.Write("function ASPNetMangledName(sName) " + Environment.NewLine);
output.Write("{" + Environment.NewLine);
output.Write(oBuilder.ToString());
output.Write("}" + Environment.NewLine);
output.Write("</script>" + Environment.NewLine);
}
}
}
This control generates a Javascript function called ASPNetMangledName() which you can use when you are coding your Javascript.
Example:
<%@ Register TagPrefix="jquery" Namespace="JQueryASPNET" Assembly="JQueryASPNET" %>
<asp:Content ID="Content1" ContentPlaceHolderID="contentPlaceHolderContent" Runat="Server">
<jquery:ASPNETJSNameHandler id="jsnamehandler" runat="server" />
...
...
<asp:HiddenField ID="serieid" runat="server" />
<asp:HiddenField ID="divpart" runat="server" />
...
...
alert( $('#' + ASPNetMangledName('serieid') ).val() );
As you can see, the control we want to work with from our JavaScript has a asp.net id of serieid - and that's what we are using. However, we call ASPNetMangledName('serieid') instead of referencing it directly.
In our codebehind (I have not implemented any designtime editing of this control)
jsnamehandler.AddControl(serieid);
jsnamehandler.AddControl(divpart);
we add the controls we want to use from javascript to the jsnamehandler control. Which, during render, creates a javascript looking like this:
<script type="text/javascript">
function ASPNetMangledName(sName)
{
if ( sName == 'serieid' ) return 'ctl00_contentPlaceHolderSide_serieid';
if ( sName == 'divpart' ) return 'ctl00_contentPlaceHolderSide_divpart';
}
</script>
Some disclaimers:
a) it doesn't work on templated, databound controls
b) I have been lazy, could have created a more robust control with designtime support etc
c) no download available. All code is here
d) cause I do have ideas on how to make this control really useful and simple to use - however that might be in the future