(This is a duplicate of a post I added to the Telerik forums)
I’m building a control that extends the RadComboBox to use a RadTreeView as the child element (it’s a tree combobox, basically – http://demos.telerik.com/aspnet-ajax/treeview/examples/functionality/treeviewcombobox/defaultcs.aspx).
The control uses a lot of client side JavaScript to provide things like autocomplete and entering freehand text for items that are marked to accept ‘other’ text.
Everything works great except for issues I’m having looking up one object from the other in JS. The markup is the standard that Telerik uses in their demo and suggests in their sample materials:
<div class="MyControl">
<asp:Label AssociatedControlID="RadComboBox1" Text="Field label: " runat="server" ID="treeListLabel" />
<telerik:RadComboBox ID="RadComboBox1" runat="server" CssClass="SearchableTreeCombo">
<ItemTemplate>
<div id="div1">
<telerik:RadTreeView ID="RadTreeView" runat="server" CssClass="SearchableTreeView" />
</div>
</ItemTemplate>
<Items>
<telerik:RadComboBoxItem runat="server" Value="RadComboBoxItem1" />
</Items>
</telerik:RadComboBox>
</div>
The HTML that gets emitted looks like this, however:
<html>
<body>
<form>
<div class="rcbSlide">
<div id="RadComboBox1_DropDown" class="RadComboBoxDropDown" ></div>
</div>
<div class="MyCustomControl">
<label for="RadComboBox1" id="treeListLabel">Field Label: </label>
<div id="RadComboBox1" class="RadComboBox RadComboBox_Default SearchableTreeCombo">
<input id="RadComboBox1_ClientState" name="RadComboBox1_ClientState" type="hidden">
</div>
</div>
</form>
</body>
</html>
The problem is that the RadComboBox appears to inject the dropdown contents far away from the actual control container (they are within the ‘rcbSlide’ div directly after the form tag is opened).
Since this is a control, it may appear multiple times on a single form, so I’d like to use JavaScript that operates using relative position. To complicate matters, I am also placing these controls dynamically in codebehind. This makes tracking control IDs a lot more tedious (but still doable).
For example, I want to have a function like this:
function GetRadComboBoxFromRadTreeViewElement(treeViewElement) {
var htmlRoot = $(treeViewElement).closest('div.MyCustomControl'); // walk up to control container
var comboBoxDiv = $(htmlRoot).find('div.SearchableTreeCombo'); // find ComboBox container
return $find($(comboBoxDiv).attr('id')); // look up ComboBox object from containing div id
}
Basically, given some element from within the TreeView (which is in the dropdown ‘rcbSlide’ div), I’d like to walk up the DOM tree until I hit the control container, and from there I can locate the divs where the ComboBox or TreeView live and load them via $find to gain access to their client side APIs.
This blows up since the dropdown is rendered outside the control container – I can’t use this method to lookup one or the other.
So, my question has 2 parts:
1. Can you change where the RadComboBox emits its dropdown elements? Specifically, can I force them to be rendered inside (or within a level) of the actual RadComboBox?
2. Is there another strategy I can employ to try and make my JS behave relatively?
The only solution I can think of is to emit a copy of the JavaScript for each instance of the control and set specific control IDs for each copy of the JS (using string formatting expression when the control is rendered). This obviously bloats the HTML and adds potentially tens of kilobytes of redundant JavaScript to every page that only differs in a few small places.
I realized that the client API provides everything needed to perform a one-way lookup from ComboBox to its dropdown element. The rest can be done using jQuery and the each() function:
I added a little more description on the Telerik forums (see link in my question).
Unlikely anyone will ever need this for anything, but I’m leaving the code here just in case – this one had me scratching my head for days.