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?
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
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!
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