Kendo MultiSelect Virtualization: -Displaying Selected Items First without breaking Virtualization

0 Answers 32 Views
MultiSelect
Joe
Top achievements
Rank 1
Joe asked on 21 Feb 2025, 11:01 AM

function GetUsers() {
    $("#msUsers").kendoMultiSelect({
        placeholder: "Select Users...",
        autoClose: false,
        autoWidth: true,
        /*   tagMode: "none",*/
        dataTextField: "UserName",
        dataValueField: "UserId",
        virtual: {
            itemHeight: 40,
            mapValueTo: "dataItem",
            valueMapper: function(options) {
                var ids = options.value;

                if (!ids.length) {
                    options.success([]);
                    return;
                }

                $.ajax({
                    url: "/Home/GetUserByIds",
                    traditional: true,
                    data: {
                        ids: ids
                    },
                    success: function(response) {

                        if (!response.length) {
                            options.success([]);
                            return;
                        }
                        options.success(response);
                    },
                    error: function(xhr) {
                        console.log("Error:", xhr.responseText);
                    }
                });
            }
        },
        dataSource: {
            transport: {
                read: {
                    url: "/Home/BindUsers",
                    dataType: "json",
                    data: function(options) {
                        return {
                            skip: options.skip,
                            take: options.take,
                            filter: options.filter
                        }
                    }
                },
                parameterMap: function(data, action) {
                    if (action === "read") {
                        return {
                            take: data.take,
                            skip: data.skip,
                            filter: data.filter && data.filter.filters && data.filter.filters[0] ?
                                data.filter.filters[0].value :
                                "" // Default to empty if no filter is applied
                        };
                    } else {
                        return data;
                    }
                }
            },
            schema: {
                data: "Data",
                total: "Total"
            },
            pageSize: 40,
            serverPaging: true,
            serverFiltering: true
        },
        enable: false,
        open: function(e) {

            debugger;
            var multiselect = this;
            var selectedValues = multiselect.dataItems(); // Get the selected value objects

            if (selectedValues.length) {
                var dataSource = multiselect.dataSource;


                var currentData = dataSource.view();


                const selectedUserIds = new Set(selectedValues.map(selected => selected.UserId));


                var remainingUsers = currentData.filter(user =>
                    user.UserId && !selectedUserIds.has(user.UserId)
                );


                var sortedData = selectedValues.concat(remainingUsers);
                console.log(sortedData);


                dataSource.data(sortedData); // THIS BREAKS VIRTUALIZATION!
            }

        },

        height: 400,       
    });
}

I am using a Kendo MultiSelect widget with virtualization to handle a large dataset.
The issue I am facing is that when the multiselect dropdown is opened, selected items that are not part of the currently loaded subset are not displayed. 




I need to ensure that all selected items are displayed first without breaking virtualization.

How can I ensure that all selected items are displayed first in a virtualized Kendo MultiSelect without breaking virtualization? Is there a way to dynamically load selected items and merge them with the current dataSource data?
Neli
Telerik team
commented on 26 Feb 2025, 07:32 AM

Hi Joe,

If the valueMapper is configured correctly and a value is set, the MultiSelect will automatically scroll to the value item. Even if it is not on the first page. Here is a screencast demonstrating the behavior - https://go.screenpal.com/watch/cTnT2hn1nff.

You can check the Dojo exapmple linked here - https://dojo.telerik.com/osFSTQQk.

Could you please let me know what is the expected behavior in your scenario?

Looking forward to your reply.

Regards,

Neli

Joe
Top achievements
Rank 1
commented on 26 Feb 2025, 04:32 PM

Hello Neli,

Thank you for your response! :)

Yes, I understand that the MultiSelect automatically scrolls to the selected item based on the example, video, and documentation: Telerik Docs.

However, as I mentioned, my requirement is to display all selected values on the first page (as I used to do before enabling virtualization).

To achieve this, I am now sending an ordered list of items from the backend, with selected values appearing first.

Thanks again!

Nikolay
Telerik team
commented on 03 Mar 2025, 10:19 AM

Hi Joe,

Since Kendo MultiSelect with virtualization fetches data in chunks, you need to ensure that:

 - Selected items are preloaded before fetching the virtualized data.
 - The virtualized list remains functional without duplicating selected items.

A possible solution is to merge selected items with virtualized data

Modify Your Backend API:

 - Return selected items first, followed by the paginated data.
 - Ensure selected items do not appear again in pagination to avoid duplicates.

Modify DataSource Handling in Kendo UI:

When initializing the MultiSelect, merge selected items into the first page of the DataSource.
Ensure valueMapper correctly resolves selected values from the server.

$("#msUsers").kendoMultiSelect({
    placeholder: "Select Users...",
    autoClose: false,
    dataTextField: "UserName",
    dataValueField: "UserId",
    virtual: {
        itemHeight: 40,
        mapValueTo: "dataItem",
        valueMapper: function (options) {
            $.ajax({
                url: "/Home/GetUserByIds",
                traditional: true,
                data: { ids: options.value },
                success: function (response) {
                    options.success(response);
                }
            });
        }
    },
    dataSource: new kendo.data.DataSource({
        transport: {
            read: function(options) {
                $.ajax({
                    url: "/Home/BindUsers",
                    dataType: "json",
                    data: {
                        skip: options.data.skip,
                        take: options.data.take,
                        filter: options.data.filter
                    },
                    success: function(response) {
                        let selectedItems = response.selected || [];
                        let paginatedData = response.data || [];

                        // Merge selected items at the top, avoiding duplicates
                        let allData = [...selectedItems, ...paginatedData.filter(item => 
                            !selectedItems.some(selected => selected.UserId === item.UserId)
                        )];

                        options.success({ Data: allData, Total: response.total });
                    }
                });
            }
        },
        schema: {
            data: "Data",
            total: "Total"
        },
        serverPaging: true,
        serverFiltering: true,
        pageSize: 40
    })
});

Beckend API response:

{
    "selected": [
        { "UserId": 1, "UserName": "John Doe" },
        { "UserId": 2, "UserName": "Jane Smith" }
    ],
    "data": [
        { "UserId": 3, "UserName": "Michael Brown" },
        { "UserId": 4, "UserName": "Sarah Johnson" }
    ],
    "total": 100
}

Regards,

Nikolay

No answers yet. Maybe you can help?

Tags
MultiSelect
Asked by
Joe
Top achievements
Rank 1
Share this question
or