我遇到一个非常奇怪的问题,当下拉列表更改时,会调用错误的绑定(bind)处理程序。我正在使用 Knockout 3.1 和 jQuery 1.9.1。我们有一组级联下拉菜单,可以更轻松地找到员工。
这就是发生的事情。当页面加载时,每个处理程序都会按预期调用。当我更改 #AssignedDepartment
中的值时,将调用 serviceAreaSelect
处理程序,而不是按预期调用 departmentSelect
。 departmentSelect
根本没有被调用,需要调用它才能正确填充#AssignedServiceAreaName
下拉列表。但是,当我对 #AssignedServiceAreaName
进行更改时,将调用 serviceAreaSelect
并按预期工作。
这里可能发生了什么?这段代码在 Knockout 2.x 中运行良好。
这是三个级联下拉列表系列的三个处理程序中的两个。
// Department Selected
ko.bindingHandlers.departmentSelect = {
update: function (element, valueAccessor, allBindingsAccessor, vm) {
var el = $(element).find("option:selected");
console.log("Department Selected: ", el.val());
if (el.length > 0) {
vm.deptName(el.text());
$.get('/customerservice/jsonproxy/servicearealist', { deptID: el.val() }, function (response) { vm.ServiceArea(response); }, 'json');
}
}
}
// Service Area Selected
ko.bindingHandlers.serviceAreaSelect = {
update: function (element, valueAccessor, allBindingsAccessor, vm) {
var el = $(element).find("option:selected");
console.log("Service Area Selected: ", el.val());
if (el.length > 0) {
vm.ServiceAreaName(el.text());
$.get('/customerservice/jsonproxy/employeelist', { deptID: vm.deptID, serviceAreaID: el.val() }, function (response) {
vm.EmployeeList(response[0].Employees);
vm.EmployeeList.unshift({ EmployeeName: "None Assigned", EmployeeID: "" });
}, 'json');
}
}
};
这是 HTML。
<div class="row-fluid">
<div class="span4">
@Html.MyLabelFor(m => m.Department, new { @class = "control-label" })
<select class="span12" id="AssignedDepartment" name="AssignedDepartment"
data-bind="options: dept, optionsCaption: 'Select a department', optionsValue: function (item) { return item.DepartmentID }, optionsText: function (item) { return item.DepartmentName; }, value: deptID, departmentSelect: deptID"></select>
<span data-bind="text: deptID"></span><span data-bind=" text: deptName"></span>
@Html.HiddenFor(m => m.Department, new { data_bind = "value: deptName" })
@Html.HiddenFor(m => m.DepartmentCode, new { data_bind = "value: deptID" })
</div>
<div class="span4">
@Html.MyLabelFor(m => m.ServiceArea, new { @class = "control-label" })
<select class="span12" id="AssignedServiceAreaName" name="AssignedServiceArea" data-bind="options: ServiceArea, optionsCaption: 'Select a Service Area', optionsValue: function (item) { return item.ServiceAreaID; }, optionsText: function (item) { return item.ServiceAreaName; }, value: ServiceAreaID, serviceAreaSelect: ServiceAreaID"></select>
@Html.HiddenFor(m => m.ServiceArea, new { @data_bind = "value: ServiceAreaName" })
@Html.HiddenFor(m => m.ServiceAreaCode, new { @data_bind = "value: ServiceAreaID" })
@*<span data-bind="text: ServiceAreaID"></span><span data-bind=" text: ServiceAreaName"></span>*@
</div>
<div class="span4">
@Html.MyLabelFor(m => m.Employee, new { @class = "control-label" })
<select class="span12" id="AssignedEmployee" name="AssignedEmployee" data-bind="options: EmployeeList, optionsCaption: 'None Assigned', optionsValue: function (item) { return item.EmployeeID; }, optionsText: function (item) { return item.EmployeeName; }, value: EmployeeID, employeeSelect: EmployeeID"></select>
@*<span data-bind="text: EmployeeID"></span><span data-bind=" text: EmployeeName"></span>*@
@Html.HiddenFor(m => m.Employee, new { data_bind = "value: EmployeeName" })
@Html.HiddenFor(m => m.EmployeeID, new { data_bind = "value: EmployeeID" })
</div>
</div>
最佳答案
更新
回调旨在重绘 DOM 以响应模型更改,而不是在 DOM 更改时更新模型的位置
(正如您的代码所暗示的那样)。
仅在 update
回调中读取模型的值以更新 DOM,切勿在 update
回调中更改模型。
value
绑定(bind)(值:deptID)将 DOM 与模型(deptID)同步,您不需要另一个绑定(bind)处理程序。
您想要的只是在模型更改时执行某些操作
。
- 摆脱
ko.bindingHandlers.departmentSelect
并且 ko.bindingHandlers.serviceAreaSelect 和ko.bindingHandlers.employeeSelect
- 移除绑定(bind)
departmentSelect: deptID
,serviceAreaSelect: ServiceAreaID
和employeeSelect:员工ID
。 - 按照您自己的答案建议执行模型中的逻辑。
是的,您的部分代码仍然不是 ko
风格,即 self.deptName($('#AssignedDepartment option:selected').text())
.
理想情况下,在 ko 应用中,所有 DOM 操作都应隐藏在 bindingHandler 的 init
和 update
回调中。
有两种方法可以修复它:
A) 自动更新 deptName。
self.deptID.subscribe(function (val) {
if (val !== undefined && val !== null) {
$.get('/customerservice/jsonproxy/servicearealist', { deptID: val }, function (response) {
self.ServiceArea(response);
if (response.length === 1) {
self.ServiceAreaID(response[0].ServiceAreaID);
}
}, 'json');
}
});
// deptName is another representation of deptID
self.deptName = ko.computed(function() {
// I don't know whether your dept is observableArray or plain array
var depts = ko.unwrap(self.dept);
var currentOne = ko.utils.arrayFirst(depts, function(d) {
return d.DepartmentID == self.deptID();
});
return currentOne && currentOne.DepartmentName;
});
B) 更改模型,不捕获 deptID,捕获整个 deptSelected 对象。
//self.deptID = ko.observable();
self.deptSelected = ko.observable();
self.deptSelected.subscribe(function (newDept) { /* ajax */ });
// optionsText: 'DepartmentName' is enough, no need a mapping function.
<select class="span12" id="AssignedDepartment" name="AssignedDepartment"
data-bind="options: dept, optionsCaption: 'Select a department',
optionsText: 'DepartmentName', value: deptSelected"></select>
<!-- ko with: deptSelected -->
<span data-bind="text: DepartmentID"></span>
<span data-bind="text: DepartmentName"></span>
@Html.HiddenFor(m => m.Department, new { data_bind = "value: DepartmentName" })
@Html.HiddenFor(m => m.DepartmentCode, new { data_bind = "value: DepartmentID" })
<!-- /ko -->
关于javascript - 调用了错误的 BindingHandler,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24998575/