This morning, while I was creating a simple ASP.NET page, I fought a couple of hours versus a GridView
that apparently worked in strange ways.
Problem Description
The problem I encountered seemed to be the wrong setting of the property “ID
” of the client-side controls. Generally, the ASP.NET engine (prior to version 4.0) takes full charge to change the ID to avoid duplication, so that they are always unique. Particularly in the case of a GridView
fact, for a control that we insert with ID = “txtSelectedValue”
, and that is repeated for each row of the grid, will have a ClientID
like this:
gridTest1_GridView1_ctl02_txtSelectedValue
This morning, I spent some time to figure out why the control was instead generated in this way:
<input id="txtSelectedValue" type="text" name="txtSelectedValue" />
Code Description
The GridView
included a column with a ComboBox
which was to run a JavaScript function to select a value. To better understand, we immediately see the code in detail:
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:TextBox runat="server" ID="txtSelectedValue" Text="" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:DropDownList runat="server" ID="ddlChoice">
<asp:ListItem Text="--" />
<asp:ListItem Text="text1" />
<asp:ListItem Text="text2" />
<asp:ListItem Text="text3" />
<asp:ListItem Text="text4" />
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
</Columns>
and this is the JavaScript function:
function selectChoice(ddl, textboxID) {
var chosenoption = ddl.options[ddl.selectedIndex];
if (chosenoption.value != 'nothing') {
document.getElementById(textboxID).value = chosenoption.value;
}
}
Wanting to add the JavaScript function to DropDownList
programmatically, I chose to act on the OnRowCreated
grid event like this:
protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DropDownList ddlChoice = e.Row.FindControl("ddlChoice") as DropDownList;
TextBox txtSelectedValue = e.Row.FindControl("txtSelectedValue") as TextBox;
string jScript = "selectChoice(this, '{0}');";
ddlChoice.Attributes.Add("onchange", string.Format(jScript, txtSelectedValue.ClientID));
}
}
The example shown here may have little practical significance, but in the daily demands we may be in a similar situation.
As you can see from the code, changing the value of the ComboBox
, we act on the client side via the onchange
event of <select>
control to copy the value into another HTML control, and in this way you avoid unnecessary PostBack
of the ASPX page, and avoid requests and execution of the code by the ASP.NET engine.
Having a set of controls all with the same id, of course the JavaScript function returns an error to the following line:
document.getElementById(textboxID).value = chosenoption.value;
because the getElementById
method returns the first HTML control with the specified id, thereby defeating the entire utility function. And here’s the wrong line:
ddlChoice.Attributes.Add("onchange", string.Format(jScript, txtSelectedValue.ClientID));
Probably, I think of that, the ASP.NET engine at this point did not create unique IDs, and with reference to the control’s ClientID
property, probably, I again thought, the ASP.NET engine decides to keep the static ID. In fact, merely commenting on the line above, all work normally.
Solution
So how to send the TextBox
control’s ID to the JavaScript function?
Referring to my few neurons still working, I seemed to remember that the RowCreated
event is raised before RowDataBound
, so I figured that postponing the use of the ClientID
property, I might have solved the problem.
In doing so, it was enough to move the code written in OnRowCreated
delegate in OnRowDataBound
delegate, to get the desired result. Here is the code generated in this case:
<tr>
<td>
<input name="gridTest1$GridView1$ctl03$txtSelectedValue"
type="text" id="gridTest1_GridView1_ctl03_txtSelectedValue" />
</td>
<td>
<select name="gridTest1$GridView1$ctl03$ddlChoice"
id="gridTest1_GridView1_ctl03_ddlChoice"
onchange="selectChoice(this, 'gridTest1_GridView1_ctl03_txtSelectedValue');">
<option value="--">--</option>
<option value="text1">text1</option>
<option value="text2">text2</option>
<option value="text3">text3</option>
<option value="text4">text4</option>
</select>
</td>
</tr>
Conclusion
I do not have in-depth studies to understand this behavior in detail, but as we know … time is short and the important thing is … … everyone lived happily ever!!