This is a migrated thread and some comments may be shown as answers.

[Solved] RadCombo in Grid client side update

4 Answers 371 Views
ComboBox
This is a migrated thread and some comments may be shown as answers.
Mike
Top achievements
Rank 1
Mike asked on 03 Nov 2009, 07:09 AM
I have been struggling with putting the combo into a grid and doing a client side autocomplete for a day now.  I dont see any samples on this which makes me wonder if no one is doing this.

Here is what I am trying to do:  I have grid that is bound to a datatable server side, in the datatable there are two related columns ClassID, Class.  These are are really one data value for a lookup. I have a template column defined as follows.

<telerik:GridTemplateColumn HeaderText="Class" UniqueName="Class" SortExpression="Class" ShowSortIcon="true" HeaderStyle-Width="200">     
    <ItemTemplate>    
        <asp:Label ID="Label1" runat="server" Text='<%# Eval("Class") %>' /> 
    </ItemTemplate>   
    <EditItemTemplate>    
        <telerik:RadComboBox ID="ClassCombo" runat="server" Width="190px" Height="200px" MarkFirstMatch="true" 
            OnClientItemsRequested="OnClientItemsRequested" OnClientItemsRequesting="OnClientItemsRequesting" OnClientDropDownClosed="OnClientDropDownClosed"   
            OnClientSelectedIndexChanged="OnClientSelectedIndexChanged" 
            EnableLoadOnDemand="true" AllowCustomText="false" > 
            <ExpandAnimation Type="none" /> 
            <CollapseAnimation Type="none" /> 
            <WebServiceSettings Path="/Lookup.asmx" Method="Classes"  /> 
        </telerik:RadComboBox> 
    </EditItemTemplate>   
</telerik:GridTemplateColumn> 

Here is the javascript for lookups:
function OnClientItemsRequesting(sender, args){  
    startTime = new Date();  
}  
 
function OnClientItemsRequested(sender, args){  
    var endTime = new Date();  
}  
 
function OnClientSelectedIndexChanged(sender, args) {  
    var item = args.get_item();  
    var text = item.get_text();  
    var val = item.get_value();  
 
     alert(val);  
}  
              
              
function OnClientDropDownClosed(sender, args)  {
  
    sender.clearItems();  
                  
    if(args.get_domEvent().stopPropagation)  
        args.get_domEvent().stopPropagation();  

The lookup service works just fine, if you type in the box it pulls back matching rows and displays them in the combo and I can select the item. 

The two things I cannot figure out. 
1. How to populate the combo with the initial value, I could do this server side when the edit postback comes in.

2. This is the big one as I cannot figure out a workaround.  How do I get the value of the selected item back into the form field on the client?  In my code, I put the statement alert(val);  in the selection and that has the correct value in it when an item is selected; I just cant figure out how to get it into the form field. 

None of the samples show a client side autocomplete combo populated by a service inside of a grid. 


4 Answers, 1 is accepted

Sort by
0
Veselin Vasilev
Telerik team
answered on 05 Nov 2009, 01:13 PM
Hello Mike,

Please find attached a sample project of using a load on demand combobox in RadGrid.

All the best,
Veselin Vasilev
the Telerik team

Instantly find answers to your questions on the new Telerik Support Portal.
Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
0
Mike
Top achievements
Rank 1
answered on 05 Nov 2009, 04:05 PM
That does not do it, that is a server side update which would cause a partial postback every time someone does a search.

Another way to ask this question in a more generic fashion, how do I set the value of an edit row on the client.  The kicker being I wont be in an event raised by the grid. From the selection changed event of the combo box, find the grid figure out which row the combo
box is in.
Here is the quick psedo code
find the clientstateid of the combo box
foreach row in grid.rows
    check if there is a combobox in the row for the correct field
    find the clientstateid of that combo box
    if combo.clientstatid = editcombo.stateid
        row = currentRow;
        get_selectedValue;

This works up to here: now, how do i set the KEY (not text value) of the underlying record.  I found a private field on the grid that has all the rows and their data in it but setting key here does not persist on update.  So, now that I have my selected key value in javascript on the browser how do I set the field value on the client side so when I post the row update it will persist?


I need to do this all ajax style in the browser,  I have figured out how to make the telerik framework do 99% of the work but its still a bit hacky.   Essentially I have to fool the combo box on the server side so I can bind it server side, then the rest just works.  I can post my workaround and the reason it has to be done that way later.

0
Mike
Top achievements
Rank 1
answered on 07 Nov 2009, 05:25 PM
Well, here is my only solution to getting this to work.

My datastructure looks like this

ID = The row id of the item being bound to
ClassID = The id of the lookup item
Class = The text of the lookup item
.... other non important columns

Here is the combo column declaration:
You have to bind to classid or the data field does not get generated on the client side
<telerik:GridTemplateColumn HeaderText="Class" UniqueName="Class" SortExpression="Class" ShowSortIcon="true" HeaderStyle-Width="200" DataField="ClassID">     
    <ItemTemplate>    
        <asp:Label ID="Label1" runat="server" Text='<%# Eval("Class") %>' /> 
    </ItemTemplate>   
    <EditItemTemplate>    
        <telerik:RadComboBox ID="ClassCombo" runat="server" Width="190px" Height="200px" MarkFirstMatch="true" OnDataBinding="ClassComboBinding" OnDataBound="ClassComboBound" 
            EnableLoadOnDemand="true" AllowCustomText="false" SelectedValue='<%# Bind("ClassID")%>'>  
            <ExpandAnimation Type="none" /> 
            <CollapseAnimation Type="none" /> 
            <WebServiceSettings Path="/Lookup.asmx" Method="Classes"  /> 
        </telerik:RadComboBox> 
    </EditItemTemplate>   
</telerik:GridTemplateColumn> 


This callback is called before the combo binds.  I have to cycle through all my data rows and add a lookup for any value that is being used.  I dont which item is binding so I can load just one, since my grid only has 20 items in it at a time this works.  If you dont do this then the radcombo will throw an exception when it binds and cannot find an item in the combo box items to display. 
protected void ClassComboBinding(object sender, EventArgs e)  
{  
 
    RadComboBox combo = sender as RadComboBox;  
    if (combo == null)  
        return;  
 
    combo.Items.Clear();  
 
    HashSet<Guid> ids = new HashSet<Guid>();  
    foreach (DataRow row in ModelClassSource.Table.Rows)  
    {  
        Guid cid = row.GetSafeGuid("ClassID");  
        if (!LookupCache.ClassList.ContainsKey(cid))   
            continue;  
 
        if (ids.Contains(cid))   
            continue;  
 
        RadComboBoxItem rcb = new RadComboBoxItem(row["Class"].ToString(), cid.ToString());  
        combo.Items.Add(rcb);  
    }  


This callback is executed after the combo has been bound and the matching item selected.  So what I am doing here is removing all the items that did not get selected.  This way they wont get transmitted back to the client wasting the bandwidth.
protected void ClassComboBound(object sender, EventArgs e)  
{  
    RadComboBox combo = sender as RadComboBox;  
    if (combo == null)  
        return;  
 
    foreach (var item in combo.Items.ToArray())  
    {  
        if (item != combo.SelectedItem)  
            combo.Items.Remove(item);  
    }  


The rest is handled by the radcombo because it is bound to a service.  What I really need to make this method work better is a callback that allows me to provide the single item that will go in combo box.  In the combo code where it binds it should check if the item is present in the collection, if not raise an event that allows me to provide the item.  If I dont provide the item it should not throw an the exception Selection out of range - Parameter name: value.  

By the way, this exception comes from inside the PerformDataBinding method:  Since I have to bind the combo to create the field, I cannot get past this without adding all the items that are needed for every row. 
RadComboBoxItem item = this.FindItemByValue(this.cachedSelectedValue);  
if (item == null)  
{  
    throw new ArgumentOutOfRangeException("value""Selection out of range");  
}
0
Mike
Top achievements
Rank 1
answered on 07 Nov 2009, 05:31 PM
For the sake of completeness, here is my attempt at doing this all client-side.  This is the combo box selected index changed event. What I was trying to do is set the value of the underlying field on the client side.  Then when the user clicks update I would expect to get my values in the postback. In the last piece where I set the key value, it does not work.  The ClassID is set but it is not sent in the postback.  This is where I figured out  (through dom inspection) I had to bind the combo to get the field to show up client side. Once the field was on the client I did not need to do all this because the RadComboBox handled the field change for me.

function OnClientSelectedIndexChanged(sender, args) {  
 
    //the combo box item that was selected  
    var item = args.get_item();  
      
    //the values from the combo  
    var text = item.get_text();  
    var val = item.get_value();  
 
    //the state field the combo box is bound to  
    var seek = sender.get_clientStateFieldID();  
      
    debugger;  
    //get the grid and master table  
    var grid = $find('<%=ClassGrid.ClientID %>');  
    var master = grid.get_masterTableView();  
 
      
    //all the rows from the grid  
    var rows = master.get_dataItems();  
    var cnt = rows.length;  
    for(var i=0;i<cnt-1;i++) {  
      
        //get the row and check for a class combo control  
        var row = rows[i];  
        var ctrl = row.findControl('ClassCombo');  
 
        if (ctrl != null) {  
 
            //There is a control, check to see if it has the same state field id  
            //as the combo that raised the event  
            var check = ctrl.get_clientStateFieldID();  
 
            if (seek == check) {  
                debugger;  
 
                //value before the change, just here to show how to 'correctly' get the value,   
                //unfortunatly I dont see an equivalent setDataKeyValue method  
                var classID = row.getDataKeyValue('ClassID');   
 
                //Cant find a set method  
                grid._clientKeyValues[i]['ClassID'] = val;  
                alert('set value to ' + val);  
            }  
        }     
    }  

Tags
ComboBox
Asked by
Mike
Top achievements
Rank 1
Answers by
Veselin Vasilev
Telerik team
Mike
Top achievements
Rank 1
Share this question
or