javascript - 调用了错误的 BindingHandler

标签 javascript jquery knockout.js

我遇到一个非常奇怪的问题,当下拉列表更改时,会调用错误的绑定(bind)处理程序。我正在使用 Knockout 3.1 和 jQuery 1.9.1。我们有一组级联下拉菜单,可以更轻松地找到员工。

这就是发生的事情。当页面加载时,每个处理程序都会按预期调用。当我更改 #AssignedDepartment 中的值时,将调用 serviceAreaSelect 处理程序,而不是按预期调用 departmentSelectdepartmentSelect 根本没有被调用,需要调用它才能正确填充#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)处理程序。

您想要的只是在模型更改时执行某些操作

  1. 摆脱ko.bindingHandlers.departmentSelect并且 ko.bindingHandlers.serviceAreaSelect 和 ko.bindingHandlers.employeeSelect
  2. 移除绑定(bind) departmentSelect: deptID, serviceAreaSelect: ServiceAreaIDemployeeSelect:员工ID
  3. 按照您自己的答案建议执行模型中的逻辑。

是的,您的部分代码仍然不是 ko 风格,即 self.deptName($('#AssignedDepartment option:selected').text()).

理想情况下,在 ko 应用中,所有 DOM 操作都应隐藏在 bindingHandler 的 initupdate 回调中。

有两种方法可以修复它:

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/

相关文章:

javascript - 如何在 jQuery 选择器中使用基于 scriptlet 的 id

javascript - Onclick 函数不适用于 CFINPUT 验证

javascript - 在加载包含哈希标签的链接时触发插件 swipebox

javascript - 在knockout.js中绑定(bind)多个viewmodel

javascript - KnockoutJS 正在更新数组中的所有对象,而不仅仅是一个

javascript - 向 AngularJS 中的动态嵌套列表添加新输入

javascript - AngularJS - 引用 $route 服务的导航 Controller

javascript - 程序化删除按钮

javascript - 跨浏览器填充导航菜单

javascript - jquery 或 javascript - 将文本编辑器中的文本添加到变量中