ASP.NET: Referencing ClientID in a Repeater
On my client’s project one of my tasks was to write a search engine and corresponding UI screen. The results of the search are displayed using an asp:Repeater control in a pattern similar to Google. One more requirement is a section that pops open to reveal additional, less-frequently-used actions. Sort of a “dropdown” of more options.
I thought I would use a hyperlink with a call to javascript that toggles the display of a <div>. It seemed like the best solution within the context of the existing page.
With that in mind, I added some javascript to my ASP.NET page (using RegisterClientScriptBlock) without a problem. But when it came to adding the “more” link and the show/hide div, I ran into a serious issue.
What I really wanted to do in the repeater’s ItemTemplate was:
<ItemTemplate>
<a href="javascript:toggleDisplay('<%=pnlMoreLinks.ClientID%>');">show / hide</a>
<asp:Panel runat="server" ID="pnlMoreLinks" CssClass="morelinks">
Show and hide me!
</asp:Panel>
<ItemTemplate>
My thought was that it would render code to the browser along the lines of:
<a href="javascript:toggleDisplay( 'ctl00_ContentPage_Repeater_ctl01_pnlMoreLinks');">show / hide</a>
<div id="ctl00_ContentPage_Repeater_ctl01_pnlMoreLinks" class="moreLinks">
Show and hide me!
</div>
The problem is that causes a compile error:
The name 'pnlMoreLinks' does not exist in the current context
Not good. Outside of the repeater, the <%=pnlMoreLinks.ClientID%> works beautifully. Inside the repeater: compile error. It seems the reference to the asp:panel is not available to other controls in the designer. In case you were wondering, proximity had no effect either.
A quick check with the other smart people led to no real epiphanies though the designer. In the end, I manually set the reference in the link to the ClientID of the panel through the ItemDataBound event on the repeater. In the code behind, this method lets you control the formatting of each row as its being rendered. The ClientID of the panel is available at this point of the page’s life cycle.
protected void rptSearchResults_ItemDataBound(object sender, RepeaterItemEventArgs e) {
HyperLink link = (HyperLink)e.Item.FindControl("lnkMoreLinks");
Panel panel = (Panel)e.Item.FindControl("pnlMoreLinks");
if (panel != null && link != null)
link.NavigateUrl = "javascript:toggleDisplay('" + panel.ClientID + "');";
}
The repeater’s ItemDataBound method has been invaluable to me in a few other tasks… having more control of the repeater than is provided by the designer and data binding is essential to usable, well-built web apps.
And now I have a hide-able div in a repeater control. Sweet.