MultiColumnComboBox - ServerSorting and ServerPaging: wrong record selection

1 Answer 22 Views
MultiColumnComboBox
Stefan
Top achievements
Rank 1
Iron
Iron
Veteran
Stefan asked on 31 Jan 2022, 02:10 PM

We're using the MultiColumnComboBox with a Custom-Datasource to utilize the ServerFiltering and ServerFiltering functionality.

Now we also want to sort the data. We're using ServerSorting + Sort, and the data is sorted correctly.

Unfortunately the Combobox picks the wrong records now, as if picking the page and record before applying the sorting.

Are we doing something wrong?

This is how our MultiColumnCombobox is set up:

@(Html.Kendo().MultiColumnComboBoxFor(model => model.KUNDE_ID)
    .Columns(columns =>
    {
        columns.Add().Field("ADR_NR_CHAR").Title("Kundennummer").Width("150px");
        columns.Add().Field("adr_name1").Title("Kundenname").Width("200px");
        columns.Add().Field("adr_name2").Title("Kundenname 2").Width("200px");
        columns.Add().Field("adr_strasse").Title("Strasse").Width("200px");
        columns.Add().Field("adr_plz").Title("PLZ").Width("100px");
        columns.Add().Field("adr_ort").Title("Ort").Width("200px");
        columns.Add().Field("ntv_kz_d").Title("Land").Width("100px");
    })
    .DataValueField("ID")
    .DataTextField("adr_name1")
    .DataSource(source =>
    {
        source.Custom()
            .ServerSorting(true)
            .Sort(s => s.Add("adr_name1").Ascending())
            .ServerFiltering(true)
            .ServerPaging(true)
            .PageSize(50)
            .Type("aspnetmvc-ajax")
            .Transport(transport =>
            {
                transport.Read("ReadCustomers", "Box");
            })
            .Schema(schema =>
            {
                schema.Data("Data").Total("Total");
            });
    })
    .Filter(FilterType.Contains)
    .FilterFields(new string[] { "ADR_NR_CHAR", "adr_name1", "adr_name2", "adr_strasse", "adr_plz", "adr_ort", "ntv_kz_d" })
    .HtmlAttributes(new { @class = "form-control", style = "width:100%;" })
    .Messages(m => m.NoData("Keine Daten gefunden").Clear("Leeren"))
    .Virtual(v => v.ItemHeight(33).ValueMapper("valueMapper"))
)

1 Answer, 1 is accepted

Sort by
1
Yanislav
Telerik team
answered on 03 Feb 2022, 11:22 AM

Hello Stefan,

Such an issue appears when a data operation such as 'read', 'page', 'filter', etc. is used along with Virtualization. The limitation is noted in our Virtualization documentation for the ComboBox. The sorting data operation also falls in the scope of the limitation.Please review the following article for more information : 

https://docs.telerik.com/kendo-ui/controls/editors/combobox/virtualization#known-limitations

Since the MultiColumnComboBox is based on the ComboBox, the problem exists for it too. A possible solution is to sort the data on the server before it's sent to the client. If the data is sorted on the server, the Sort configuration in the MultiColumnComboBox won't be needed.

Another possible possible approach is to either remove the sorting : 

 .Sort(s => s.Add("adr_name1").Ascending())

or to remove the virtualization :

.Virtual(v => v.ItemHeight(33).ValueMapper("valueMapper")

 

Regards,
Yanislav
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Stefan
Top achievements
Rank 1
Iron
Iron
Veteran
commented on 03 Feb 2022, 01:56 PM

Hi Yanislav,

thank you for the info, I didn't know that it was a limitation.

Because of the amount of data underlying the ComboBox (30.000 records) we need virtualization. Is there maybe another way to use that amount of data effectively with the MultiColumnComboBox?

We tried your suggestion, removed the .Sort() function, and implemented the sorting server side. We tried with and without ServerSorting(true), too. Unfortunately the data still appears unsorted in the MultiColumnComboBox.

Our code:

@(Html.Kendo().MultiColumnComboBoxFor(model => model.KUNDE_ID)
    .Columns(columns =>
    {
        columns.Add().Field("ADR_NR_CHAR").Title("Kundennummer").Width("150px");
        columns.Add().Field("adr_name1").Title("Kundenname").Width("200px");
        columns.Add().Field("adr_name2").Title("Kundenname 2").Width("200px");
        columns.Add().Field("adr_strasse").Title("Strasse").Width("200px");
        columns.Add().Field("adr_plz").Title("PLZ").Width("100px");
        columns.Add().Field("adr_ort").Title("Ort").Width("200px");
        columns.Add().Field("LAND").Title("Land").Width("200px");
    })
    .DataValueField("ID")
    .DataTextField("adr_name1")
    .DataSource(source =>
    {
        source.Custom()
        .ServerFiltering(true)
        .ServerPaging(true)
        .ServerSorting(true)
        .PageSize(50)
        .Type("aspnetmvc-ajax")
        .Transport(transport =>
        {
            transport.Read("ReadCustomers", "Box");
        })
        .Schema(schema =>
        {
            schema.Data("Data").Total("Total");
        });
    })
    .Filter(FilterType.Contains)
    .FilterFields(new string[] { "ADR_NR_CHAR", "adr_name1", "adr_name2", "adr_strasse", "adr_plz", "adr_ort", "LAND" })
    .HtmlAttributes(new { @class = "form-control", style = "width:100%;" })
    .Messages(m => m.NoData("Keine Daten gefunden").Clear("Leeren"))
    .Virtual(v => v.ItemHeight(33).ValueMapper("valueMapper"))
)

On the server:

public JsonResult ReadCustomers([DataSourceRequest] DataSourceRequest request)
{
    return Json(db.IDTB_CUSTOMER.OrderBy(c => c.adr_name1).ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}

Result:

Stefan
Top achievements
Rank 1
Iron
Iron
Veteran
commented on 07 Feb 2022, 07:25 AM | edited

Hi Yanislav,

we finally figured it out. We

  1. had to omit deferred execution in Linq2SQL and had to get the customers with ToList() first, and
  2. had to use the same statement for the value mapper

So on the server it looks like this now:


public JsonResult ReadCustomers([DataSourceRequest] DataSourceRequest request)
{            
    return Json(Customers().ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}

public ActionResult Customers_ValueMapper(int[] values)
{
    var indices = new List<int>();

    if (values != null && values.Any())
    {
        var index = 0;

        foreach (var customer in Customers())
        {
            if (values.Contains(customer.ID))
            {
                indices.Add(index);
            }

            index += 1;
        }
    }

    return Json(indices, JsonRequestBehavior.AllowGet);
}

private List<IDTB_CUSTOMER> Customers()
{
    return db.IDTB_CUSTOMER.OrderBy(c => c.adr_name1).ToList();   
}

It's not optimal though, I wished there was a way to not load all customers into memory first, but for now it's ok.

Tags
MultiColumnComboBox
Asked by
Stefan
Top achievements
Rank 1
Iron
Iron
Veteran
Answers by
Yanislav
Telerik team
Share this question
or