I have a radcombobox that uses a headertemplate and an itemtemplate and I would like my users to be able to sort by clicking on the text from the headertemplate.
Here is the radcombobox. It works and it's pretty simple but I can't work out how to get it to sort the items based on clicking text in the header.
<telerik:RadComboBox ID="rcbEmp2" runat="server" Width="570px" AutoPostBack="true"
MarkFirstMatch="true" HighlightTemplatedItems="true" AppendDataBoundItems="true" >
<HeaderTemplate>
<ul>
<li>Employee</li>
<li>Miles</li>
<li>Shifts</li>
<li>Availability</li>
</ul>
</HeaderTemplate>
<ItemTemplate>
<ul>
<li><asp:Label runat="server" ID="lbEmpNameg" Text='<%# Eval("EmpFullName")%> '></asp:Label></li>
<li><asp:Label runat="server" ID="Label1" Text='<%# Eval("KsDistance")%> '></asp:Label></li>
<li><%# DataBinder.Eval(Container.DataItem, "ThisWeeksDemoCount")%></li>
<li><%# DataBinder.Eval(Container.DataItem, "AvailText")%></li>
</ul>
</ItemTemplate>
</telerik:RadComboBox>
Thanks in advance!
3 Answers, 1 is accepted
Hi Gavin,
To sort the items in RadComboBox you can use one of the dedicated server-side methods
- RadComboBox1.SortItems()
- RadComboBox1.Items.Sort()
Both these methods accept one parameter of type IComparer that can be used for defining a custom sorting order based on a property of the RadComboBoxItem (Text, Value, Checked, or some Custom Attributes).
I would suggest you review our Implement Custom Sorting article. There you can find a sample of Custom Sorting implementation where ComboBoxItems are ordered by their value.
To trigger the custom sorting in the current case, you can possibly use LinkButtons in the HeaderTemplate and handle their server-side Click event to execute the desired custom sorting procedure.
I hope this information will help you achieve the desired behavior.
Kind regards,
Doncho
Progress Telerik
Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.
Thanks Doncho!
I managed to get that working server side however clicking on the link buttons causes a postback and the RadComboBox to close.
Because I can't have that happen I looked at client side sorting and I found this Sorting radcombobox in client side in UI for ASP.NET AJAX | Telerik Forums
It's pretty good however because I'm using a HeaderTemplate and ItemTemplate 2 problems occured:-
1. I don't know how to get the values from the ItemTemplate to sort by them.
2. Because it is clearing the items then re-adding them back it loses the info in my ItemTemplate and only gives me the DataTextField. (Picture Below)
The sorting works but losing the other info in my ItemTemplate can't happen.
Is there a way that I can do it where it doesn't postback and it keeps the info in my ItemTemplate columns.
Thanks in advance!
Gavin
Hi Gavin,
You can use the ItemDataBound event of the Combo to store the additional fields as custom attributes of each combo Item:
Then you can use these custom attributes both to populate the combo and also to reach the specific values for each item on the client side and process them in the desired way:
Hi Doncho,
When I try to use the ItemDataBound event I get the following error.
Here is what e.Item.DataItem is returning
{ EmployeeID = 716, EmpFullName = "Feryal Allaoui", FirstName = "Feryal", LastName = "Allaoui", TrainingSpare = false, AreaSpare = false, KsDistance = "11.06", ThisWeeksDemoCount = 0, fnIEA = 0, AvailText = "" ... }
Sorry I didn't get very far before hitting this hurdle.
Cheers
Gavin
Hi Doncho,
After a lot of time and research I found that the ItemDataBound event does not work for a RadComboBox when trying to retrieve the data like this DataRowView dataItem = (DataRowView)e.Item.DataItem;
I have managed to retrieve the information in the ItemDataBound event like this.
Label lblDemoCount = item.FindControl("lblDemoCount") as Label;
string demoCount = lblDemoCount.Text;
if (!string.IsNullOrEmpty(demoCount))
{
item.Attributes["thedemoCount"] = demoCount;
}
I have also managed to add it to an array using a loop like this
tempArray[i][3] = rcbItems.getItem(i).get_attributes().getAttribute("thedemoCount");
The only thing that I cannot see how to do is put it back into the RadComboBox.
I could put it into a label or anything really but can't work it out.
Here is what I'm trying
comboItem.get_attributes().setAttribute("thedemoCount", [i][3]);
comboItem.get_attributes().setAttribute("lblDemoCount", [i][3]);
Here is where I'm trying to put it
<li class="col2g"><%# DataBinder.Eval(Container, "Attributes['thedemoCount']") %> </li>
Thanks in advance
Or I've tried here
<li class="col2g"><asp:Label runat="server" ID="lblDemoCount" Text='<%# DataBinder.Eval(Container.DataItem, "ThisWeeksDemoCount")%>' Visible="true"></asp:Label> </li>
Hi Gavin,
In the ItemDataBound you can reach the object instance that is bound to the current ComboBox item.
For instance, If ComboBox is bound to a DataTable object, the e.Item.DataItem will return the DataRowView bound to the current item. The e.Item.DataItem is holding an object of type object and it needs to be cast to the proper type. Looking at the error message you got, it seems that the Combo is bound to a collection of anonymous objects, and casting such objects as DataRowView fails.
Instead, I would suggest you consider defining a custom class with the same properties as the one currently used in the anonymous objects. Binding a collection of strongly typed objects to the RadComboBox will allow you to use the ItemDataBound event to reach each separate object instance and cast it to its type, hence reaching the values in its properties:
E.g. RadComboBox1.DataSource is set to List<MyCustomClass> and in ItemDataBound event:
MyCustomClass dataItem = e.Item.DataItem as MyCustomClass;
To be able to provide you with more accurate assistance it would be helpful if you share the current version of the RadComboBox declaration along with all the relevant code-behind logic. That way I can have a more clear overview of the specific scenario and come up with a more specific suggestion.
Hi Doncho,
I made a comment after my last one that I worked out how to get the data. I also can get it into the array using Javascript. I'm just having problems setting it.
Here is what I wrote which is also above.
Hi Doncho,
After a lot of time and research I found that the ItemDataBound event does not work for a RadComboBox when trying to retrieve the data like this DataRowView dataItem = (DataRowView)e.Item.DataItem;
I have managed to retrieve the information in the ItemDataBound event like this.
Label lblDemoCount = item.FindControl("lblDemoCount") as Label;
string demoCount = lblDemoCount.Text;
if (!string.IsNullOrEmpty(demoCount))
{
item.Attributes["thedemoCount"] = demoCount;
}
I have also managed to add it to an array using a loop like this
tempArray[i][3] = rcbItems.getItem(i).get_attributes().getAttribute("thedemoCount");
The only thing that I cannot see how to do is put it back into the RadComboBox.
I could put it into a label or anything really but can't work it out.
Here is what I'm trying
comboItem.get_attributes().setAttribute("thedemoCount", [i][3]);
comboItem.get_attributes().setAttribute("lblDemoCount", [i][3]);
Here is where I'm trying to put it
<li class="col2g"><%# DataBinder.Eval(Container, "Attributes['thedemoCount']") %> </li>
Thanks in advance
Or I've tried here
<li class="col2g"><asp:Label runat="server" ID="lblDemoCount" Text='<%# DataBinder.Eval(Container.DataItem, "ThisWeeksDemoCount")%>' Visible="true"></asp:Label> </li>
Hi,
I was just wondering if there was any update on this.
I still can't see how it can be done without post back.
Hi Gavin,
Sorry for the delay with this case.
I am attaching a sample demonstration of how you can bind multiple fields as Attributes of the ComboBox items.
Using the default server-side Sorting capabilities of the Control you can implement a custom sorting mechanism based on any of the Attributes bound to the Combo Items.
Please give it a try review the implementation and see if you can reuse the approach for the current case.
Any sorting that applies on the client side would require a custom JavaScript approach that extends the default functionalities of the control. Although such a solution could be possible, it could be quite tricky to implement and will go beyond the supported features of the Control.
To be able to run the sample you will need to add the Telerik.Web.UI.dll in the bin folder of the project.
Please let me know if any further questions come up.
Kind regards,
Doncho
Progress Telerik
Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.
Hi,
Thanks for your answer and sorry for the delay. I've spent days trying to work it out again and in the end it looks like it just can't happen. The whole point of what I'm asking is that it does not postback.
The example you gave posts back.
I can get all of the values in JS into an array, clear the old radcombobox but cannot set them again.
I've taken another approach like this.
Add this link button into the header
<asp:LinkButton ID="LinkButton2" runat="server" Text="TestSortMiles" OnClientClick="sortComboByMiles(); return false;"></asp:LinkButton>
Add this JS function
function sortComboByMiles()
{
$find("<%=RadAjaxManager16.ClientID%>").ajaxRequest('sortComboByMiles');
}
Add this in Code behind
protected void RadAjaxManager1_AjaxRequest(object sender, AjaxRequestEventArgs e)
{
{
RadComboBox rcbSuggestedEmp = sender as RadComboBox;
if (hfrcbSuggestedEmpMilesAscDesc.Value == "Asc")
{
rcbSuggestedEmp.Sort = RadComboBoxSort.Ascending;
hfrcbSuggestedEmpMilesAscDesc.Value = "Desc";
}
else
{
rcbSuggestedEmp.Sort = RadComboBoxSort.Descending;
hfrcbSuggestedEmpMilesAscDesc.Value = "Asc";
}
// rcbEmp2.SortItems(new SortComboItemsByValue());
rcbSuggestedEmp.SortItems(new SortSuggestedEmpComboItemsByMiles());
}
}
The problem is that the RadComboBox "rcbSuggestedEmp" is inside a Radgrid. So I can't find it through the ajaxrequest.
Is there any way of doing this at all? It's a simple sort of a RadComboBox that's inside a Radgrid in an ItemTemplate. Without Posting back.
Cheers
Gavin
Hi Gavin,
Using RadAjaxManager and its ajaxRequest method seems quite a suitable solution for the case.
As the RadComboBox is nested in a template you can use the RadAjaxManager API to add the needed ajax setting programmatically, refer to the following resources:
- https://docs.telerik.com/devtools/aspnet-ajax/knowledge-base/ajaxify-particular-templated-gridview-buttons
- https://demos.telerik.com/aspnet-ajax/ajaxmanager/application-scenarios/partial-ajaxification/defaultcs.aspx
Here is a sample modification of the sample code you can try:
ASPX
<telerik:RadAjaxManager ID="RadAjaxManager1" runat="server" OnAjaxRequest="RadAjaxManager1_AjaxRequest">
</telerik:RadAjaxManager>
<telerik:RadScriptBlock runat="server" ID="RadScriptBlock1">
<script>
function sortComboByMiles() {
$find("<%=RadAjaxManager1.ClientID%>").ajaxRequest('sortComboByMiles');
}
</script>
</telerik:RadScriptBlock>
<telerik:RadComboBox ID="RadComboBox1" runat="server" Width="800px" DataSourceID="SqlDataSource1" AutoPostBack="true" DataTextField="OrderID" DataValueField="OrderID" CollapseAnimation-Type="None" ExpandAnimation-Type="None" OnLoad="RadComboBox1_Load"
MarkFirstMatch="true" HighlightTemplatedItems="true" AppendDataBoundItems="true" DropDownCssClass="exampleRadComboBox" OnItemDataBound="RadComboBox1_ItemDataBound">
<HeaderTemplate>
<ul>
<li class="col1">OrderID</li>
<li class="col2">ShipName</li>
<li class="col3">ShipCountry</li>
<li class="col4">
<asp:LinkButton ID="LinkButton2" runat="server" Text="TestSortMiles" OnClientClick="sortComboByMiles(); return false;"></asp:LinkButton>
</li>
</ul>
</HeaderTemplate>
<ItemTemplate>
<ul>
<li class="col1"><%# DataBinder.Eval(Container.DataItem, "OrderID")%></li>
<li class="col2"><%# DataBinder.Eval(Container.DataItem, "ShipName")%></li>
<li class="col3"><%# DataBinder.Eval(Container.DataItem, "ShipCountry")%></li>
<li class="col4"><%# DataBinder.Eval(Container.DataItem, "Freight")%></li>
</ul>
</ItemTemplate>
</telerik:RadComboBox>
C#
protected void RadAjaxManager1_AjaxRequest(object sender, AjaxRequestEventArgs e)
{
if (e.Argument == "sortComboByMiles")
{
switch (RadComboBox1.Sort)
{
case RadComboBoxSort.None:
RadComboBox1.Sort = RadComboBoxSort.Ascending;
break;
case RadComboBoxSort.Ascending:
RadComboBox1.Sort = RadComboBoxSort.Descending;
break;
case RadComboBoxSort.Descending:
RadComboBox1.Sort = RadComboBoxSort.Ascending;
break;
}
//RadComboBox1.Sort = RadComboBoxSort.Descending;
RadComboBox1.SortItems(new SortComboItemsByValue());
RadComboBox1.OpenDropDownOnLoad = true;
}
}
protected void RadComboBox1_Load(object sender, EventArgs e)
{
var combo = sender as RadComboBox;
RadAjaxManager1.AjaxSettings.AddAjaxSetting(combo, combo);
RadAjaxManager1.AjaxSettings.AddAjaxSetting(RadAjaxManager1, combo);
RadComboBox1.OpenDropDownOnLoad = false;
}
Hi,
That all looks great and I can do that but I'm not sure if you read what I wrote.
The problem is that the RadComboBox "rcbSuggestedEmp" is inside a Radgrid. So I can't find it through the ajaxrequest.
protected void RadAjaxManager1_AjaxRequest(object sender, AjaxRequestEventArgs e)
{
if (e.Argument == "sortComboByMiles")
{
RadComboBox rcbSuggestedEmp = sender as RadComboBox;
if (hfrcbSuggestedEmpMilesAscDesc.Value == "Asc")
{
rcbSuggestedEmp.Sort = RadComboBoxSort.Ascending;
hfrcbSuggestedEmpMilesAscDesc.Value = "Desc";
}
else
{
rcbSuggestedEmp.Sort = RadComboBoxSort.Descending;
hfrcbSuggestedEmpMilesAscDesc.Value = "Asc";
}
// rcbEmp2.SortItems(new SortComboItemsByValue());
rcbSuggestedEmp.SortItems(new SortSuggestedEmpComboItemsByMiles());
}
}
How can I find the combo in the radGrid ItemTemplate through RadAjaxManager1_AjaxRequest(object sender, AjaxRequestEventArgs e)
If I can find the radcombobox in the AjaxRequestEvent above then I am home. I can do everything else but not find the Radcombobox in the RadAjaxManager1_AjaxRequest as I highlighted in yellow above.
In your code you have the following
protected void RadComboBox1_Load(object sender, EventArgs e)
{
var combo = sender as RadComboBox;
RadAjaxManager1.AjaxSettings.AddAjaxSetting(combo, combo);
RadAjaxManager1.AjaxSettings.AddAjaxSetting(RadAjaxManager1, combo);
RadComboBox1.OpenDropDownOnLoad = false;
}
However RadComboBox1 is not there because it is in a RadGrid.
Cheers
Gavin
Hi Gavin,
Embedding this customized ComboBox in a Template makes the scenario quite more complicated and tricky to implement and this might require significant time and effort.
I will invest some time experimenting with the scenario and I will come back to you with additional information.
Hi,
I have managed to get the sorting working in a stand alone radcombobox using RadAjaxManager and an ajaxrequest however the problem is that I am getting the list of data on the "OnItemsRequested" event and once I fire the sorting it works however when I go back to look into the radcombobox it fires the OnItemsRequested event again. It shouldn't be firing the event again I believe.
Here is the RadCombobox
<telerik:RadComboBox ID="rcbEmp7" runat="server" Width="570px" SortCaseSensitive="false" BackColor="blue"
MarkFirstMatch="true" HighlightTemplatedItems="true" AppendDataBoundItems="true" OnItemsRequested="rcbEmp7_ItemsRequested" EnableLoadOnDemand="True" >
<HeaderTemplate>
<ul>
<li class="col1gLengthened"><asp:LinkButton ID="lbtnRcbEmp2EmployeeHeader" runat="server" Text="Employee" OnClientClick ="sortComboByEmp(); return false;" ></asp:LinkButton></li>
<li class="col2g"><asp:LinkButton ID="lbtnRcbEmp2MilesHeader" runat="server" Text="Miles" OnClientClick="sortComboByMiles(); return false;"></asp:LinkButton></li>
<li class="col2g"><asp:LinkButton ID="lbtnRcbEmp2ShiftsHeader" runat="server" Text="# Shifts" OnClientClick="sortByShifts(); return false;"></asp:LinkButton></li>
<li class="col3g"><asp:Label ID="lbfinIEAgg" runat="server" Visible="false"></asp:Label></li>
<li class="col4g">Availability</li>
</ul>
</HeaderTemplate>
<ItemTemplate>
<ul>
<li class="col1gLengthened"><asp:Label runat="server" ID="lbEmpNameg" Text='<%# Eval("EmpFullName")%> '></asp:Label></li>
<li class="col2g"><asp:Label runat="server" ID="lblKsDistance" Text='<%# DataBinder.Eval(Container.DataItem, "KsDistance")%>'></asp:Label></li>
<li class="col2g"><asp:Label runat="server" ID="lblDemoCount" Text='<%# DataBinder.Eval(Container.DataItem, "ThisWeeksDemoCount")%>' Visible="true"></asp:Label><%# DataBinder.Eval(Container, "Attributes['thedemoCount']") %> </li>
<li class="col3g"><asp:Label ID="lbfinIEA" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "fnIEA")%>' Visible="false"></asp:Label></li>
<li class="col4g"><asp:Label ID="lbfinIEAText" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "AvailText")%>' ></asp:Label></li>
</ul>
</ItemTemplate>
</telerik:RadComboBox>
Here is the javascript for the LinkButton lbtnRcbEmp2EmployeeHeader in the header
function sortComboByEmp() {
$find("<%=RadAjaxManager16.ClientID%>").ajaxRequest('sortComboByEmpG');
}
Of course the control rcbEmp7 is in my RadAjaxManager as an updatedControl
The sorting works fine if the datasource is normal however the problem is that I have about 700 of these on the page and they each get different data so I need them to only get the data on the "OnItemsRequested" event of the radcombobox
I hope that makes sense.
Gavin
Hi Gavin,
The ItemsRequested event of the ComboBox will trigger every single time the combo needs to list the items. With the Load On Demand functionality enabled, the items are loaded every time the dropdown opens.
The best way to achieve the sorting is to make the combo request the items again by calling the combo's requestItems() method (see RadComboBox Object) and send additional information to the server such as field name and sort order. When the event is triggered, you can access the additional info in the event arguments which you can use to fetch, filter, sort the data before returning it back to the combobox.
Note: In none of the scenarios is the RadAjaxManager, RadAjaxPanel or asp:UpdatePanels are involved. the ComboBox's Load on Demand functionality already makes AJAX calls to server.
If you need further assistance implementing this, please submit a support ticket and somebody from the Team will assist you.
Hi Attila,
The thing is that I don't want the ComboBox to trigger the itemsRequested event again. The data is the same, it is just sorted differently.
In the standard scenario where I am not doing any sorting in the combobox the ItemsRequested event does not fire twice. It fires the first time I open the combobox and if I close it and open it again it will not fire a second time. That is what I want
I am guessing that the LoadOnDemand functionality sees the sorting as a postback and believes that it needs to get new data. Which it doesn't. It just needs to sort it.
Unfortunately I cannot disable the LoadOnDemand functionality.
What this means is that the combo has to get its items using LoadOnDemand then when I click an event to sort by a column and using the "ItemsRequested" event I can send the column name that I want sorted however it will postback and the combo will have to be loaded again. If the user then wants to sort by employee again it will have to postback again and get all of the data again. This seems like a lot when it should be a simple javascript sort.
There is no difference in me simply setting a hidden field and when the user clicks on a header item I could just set the hidden field and use that value to do my sorting with the datasource since it needs to get fresh data every time.
Am I missing something or is this a major flaw in the combobox?
Below is an example of my RadComboBox
Hi Gavin,
I have to correct myself as was wrong. Earlier I said the Combo will request the items every time the dropdown opens. Actually, the items will only be requested automatically when the DropDown opens for the first time. Then the ItemsRequested event is triggered whenever you're typing in the input (changing the input text making the combo search for items based on that - requires the complete implementation of the Load On Demand Example functionality)
Server Templates with the LoadOnDemand functionality is not supported. For the correct implementation of the Load On Demand functionality, you can follow the instructions from the Load On Demand Example or ItemsRequested articles. With this approach the data binding in items will not work.
In order to use Server-Template, you must bind the ComboBox using the DataSource + DataBind() combination. The LoadOnDemand cannot be used in this case.
The ComboBox will not not make a PostBack unless the AutoPostBack property is set to true.
<telerik:RadComboBox ID="RadComboBox1" AutoPostBack="true"
If a PostBack is made when you click on a control inside the Combo item, that is coming from the custom control. If you do not want that, you will need to prevent them from making PostBacks.
Summary
- If you want to use Server Templates, you cannot use Load On Demand.
- When using Load On Demand, you must create and add items to the ComboBox as demonstrated in the Load On Demand Example or ItemsRequested articles.
- Sorting of Items is not supported out of the box and we do not have examples to share. If you want to sort the items, you will have to implement that additionally.