Ajax更新Kendo MultiSelect数据源需触发额外服务请求才生效问题
问题根因
这个问题核心是Kendo MultiSelect的内部状态机制导致的:
- 配置
AutoBind(false)且页面加载阶段通过BindTo()绑定了初始值时,控件会缓存初始渲染的数据源状态,不会自动响应外部直接对dataSource.data()的替换操作 - 原Ajax回调仅替换了数据集,没有触发控件视图重绘,也没有处理初始选中值和新数据源的匹配逻辑,所以界面不会更新
- 用户手动输入触发
GetMembersByMemberTypeIds的read请求后,控件会自动完成内部数据源状态初始化和视图重绘,后续替换数据才会正常生效 - 原代码里的
async: false同步Ajax已经被现代浏览器标记为废弃,会阻塞主线程造成页面卡顿,不建议使用。
可行解决方案
方案1:通过Kendo官方API规范更新数据源(推荐)
不要直接修改dataSource.data(),通过官方提供的setDataSource方法更新数据源,主动触发控件重绘,同时清理无效的初始选中值,不会产生冗余请求,修正后的代码如下:
function getPsychiatrists() { // 移除async:false,使用异步回调处理逻辑,避免阻塞UI $.ajax({ url: "/CommonJsonActions/GetPsychiatrists", type: "GET", dataType: "json", success: function (result) { var multiSelect = $ddlExplainingPractitioner.data("kendoMultiSelect"); // 格式化返回数据 var resultData = $.map(result, function (v) { return { MemberId: v.MemberId, DisplayName: v.DisplayName }; }); // 清空原有无效选中值 multiSelect.value([]); // 重新绑定数据源,无需重复设置TextField/ValueField,初始化阶段已经配置完成 multiSelect.setDataSource(new kendo.data.DataSource({ data: resultData })); // 触发控件重绘 multiSelect.refresh(); } }) }
如果更新数据源后需要保留新数据集中存在的原有选中值,可以在更新前暂存原value,过滤出有效值后重新赋值:
success: function(result) { var multiSelect = $ddlExplainingPractitioner.data("kendoMultiSelect"); var oldValue = multiSelect.value(); // 暂存原有选中值 var resultData = $.map(result, function (v) { return { MemberId: v.MemberId, DisplayName: v.DisplayName }; }); multiSelect.setDataSource(new kendo.data.DataSource({data: resultData})); // 过滤出存在于新数据源中的有效值,避免无效选中 var validValue = $.grep(oldValue, function(val) { return resultData.some(function(item) { return item.MemberId == val; }); }); multiSelect.value(validValue); multiSelect.refresh(); }
方案2:模拟搜索行为触发控件初始化(临时兼容用,不推荐)
如果不想大幅修改原有逻辑,可以手动触发一次控件的搜索行为,提前完成内部状态初始化,需要注意你配置了MinLength(2),直接传空字符串无法触发搜索,需要临时调整配置:
success: function (result) { var ddlData = $ddlExplainingPractitioner.data("kendoMultiSelect"); var resultData = []; $.each(result, function (k, v) { resultData.push({ MemberId: v.MemberId, DisplayName: v.DisplayName }); }); ddlData.dataTextField = "DisplayName"; ddlData.dataValueField = "MemberId"; // 临时取消最小输入长度限制,触发一次初始化请求 ddlData.setOptions({minLength: 0}); ddlData.search(""); // 恢复原有最小输入长度配置 ddlData.setOptions({minLength: 2}); ddlData.dataSource.data(resultData); ddlData.refresh(); }
注意:该方案会额外发起一次
GetMembersByMemberTypeIds请求,存在服务端资源浪费,仅作为临时兼容方案使用。
额外优化建议
- 你给MultiSelect配置了
MaxSelectedItems(1),本质是单选场景,直接使用Kendo DropDownList会比MultiSelect更轻量,也不会出现这类多选控件特有的状态同步问题 - 移除Ajax请求中的
async: false配置,同步请求会阻塞页面所有交互,用户体验极差 - 不要在每次Ajax回调里重复设置
dataTextField和dataValueField,这两个属性在控件初始化时配置一次即可,重复赋值可能引发不可预期的状态异常
内容的提问来源于stack exchange,提问作者joseph.c
相关产品推荐
相关产品推荐

