Hi all,
Here is how to sort the multi-selector tag widget. PS: This is not really a “proper” attribute initialization script but rather a after render solution, if anyone has the proper script, please share. I played around with it but could not get it working.
Use the following script in the attribute initialization script (set and change script to your attribute id i.e the “cell id” for the attribute in the form and also remove “—–SCRIPT—–” in top/bottom. Just FYI, the forum doesn’t display code well so looks strange and codeblock used for parts of code but you should use all code within the —–SCRIPT—– top/bottom.):
-----SCRIPT-----
(function () {
"use strict";
// ===== CONFIG =====
var INPUT_ID = "YOURATTRIBUTEID"; // underlying hidden input
var TAGLIST_ID = "YOURATTRIBUTEID_taglist"; // ul containing chips
var MAX_TRIES = 40; // 40 * 100ms = 4 seconds
var TRY_DELAY = 100;
// ===== HELPERS =====
function getMultiSelect() {
var $input = $("#" + INPUT_ID);
if (!$input.length) return null;
return $input.data("kendoMultiSelect") || null;
}
function getChipLis() {
var $ul = $("#" + TAGLIST_ID);
if (!$ul.length) return [];
return $ul.children("li").get();
}
function chipText(li) {
// first span in the chip is the label
var t = $(li).find("span").first().text();
return (t == null) ? "" : String(t).trim();
}
function arraysEqual(a, b) {
if (!a || !b) return false;
if (a.length !== b.length) return false;
for (var i = 0; i < a.length; i++) {
if (String(a[i]) !== String(b[i])) return false;
}
return true;
}
// ===== CORE: SORT + APPLY =====
function sortAndApply() {
var ms = getMultiSelect();
if (!ms) return false;
// Preferred: sort using Kendo selected data items (keeps internal order consistent)
if (typeof ms.dataItems === "function") {
var items = ms.dataItems().slice();
if (!items.length) return true;
var textField = ms.options.dataTextField;
var valueField = ms.options.dataValueField;
items.sort(function (a, b) {
var ta = (a && a[textField] != null) ? String(a[textField]).trim() : "";
var tb = (b && b[textField] != null) ? String(b[textField]).trim() : "";
return ta.localeCompare(tb);
});
var sortedValues = items.map(function (it) { return it[valueField]; });
var curValues = ms.value();
if (!arraysEqual(curValues, sortedValues)) {
ms.value(sortedValues); // forces chip order
// ensure Aware/Kendo update hidden input string too
ms.trigger("change");
}
return true;
}
// Fallback: if dataItems() not available, sort DOM chips only
var lis = getChipLis();
if (!lis.length) return true;
lis.sort(function (a, b) {
return chipText(a).localeCompare(chipText(b));
});
var $ul = $("#" + TAGLIST_ID);
for (var i = 0; i < lis.length; i++) $ul.append(lis[i]);
return true;
}
// ===== BINDINGS (keep sorted) =====
function bindKeepSorted() {
var ms = getMultiSelect();
if (ms) {
// Kendo change hook (re-sort after add/remove)
try {
ms.unbind("change._awareKeepSorted");
ms.bind("change._awareKeepSorted", function () {
// Delay to allow Kendo to finalize selection before reading dataItems()
setTimeout(sortAndApply, 0);
});
} catch (e) {}
}
// Backup: observe chip list DOM changes and re-sort
var ul = document.getElementById(TAGLIST_ID);
if (ul && window.MutationObserver) {
try {
var obs = new MutationObserver(function () {
// Avoid tight loops
setTimeout(sortAndApply, 0);
});
obs.observe(ul, { childList: true });
} catch (e2) {}
}
}
// ===== START: WAIT UNTIL WIDGET EXISTS =====
var tries = 0;
(function waitUntilReady() {
tries++;
var ms = getMultiSelect();
var ul = document.getElementById(TAGLIST_ID);
// We consider it "ready" if we can see either the widget or the taglist
if (ms || ul) {
// First sort
sortAndApply();
// Keep it sorted
bindKeepSorted();
return;
}
if (tries < MAX_TRIES) {
setTimeout(waitUntilReady, TRY_DELAY);
}
})();
})();
-----SCRIPT-----