【问题标题】:Issue with knockout subscribe淘汰订阅问题
【发布时间】:2013-03-18 04:02:12
【问题描述】:

地狱,

我有一个带有子模型的复杂淘汰视图模型。以下是视图模型定义:

var DailyItems = function (data) {
var p = this;
this.Date = ko.observable(data.Date);
this.Required = ko.observable(data.Required);
this.SetupTime = ko.observable(data.SetupTime);
this.CloseTime = ko.observable(data.CloseTime);
this.MinHrsPerDay = ko.observable(data.MinHrsPerDay);
this.MaxHrsPerDay = ko.observable(data.MaxHrsPerDay);
this.WorkSegments = ko.observableArray([]);
var records = $.map(data.WorkSegments, function (x) { return new WorkShift(p, x) });
this.WorkSegments(records);

this.EnableAdd =  ko.computed(function () {
    return this.WorkSegments().length < 8;
}, this);

this.Add = function () {
    var data = {
        Parent: p,
        ID: "",
        Date: this.Date,
        Location: UNIT_ID,
        Role: "",
        EmployeeRoles: this.WorkSegments()[0].EmployeeRoles(),//add the roles of the first work segment
        ShiftStart: "",
        ShiftEnd: ""
    };
    var child = new WorkShift(p, data);
    this.WorkSegments.push(child);      
}

this.Delete = function (item) {
    this.WorkSegments.remove(item);
}
};

var WorkShift = function (parent, data) {
var self = this;
this.Parent = ko.observable(parent);
this.ID = ko.observable(data.ID);
this.Day = ko.observable(data.Day);
this.Location = ko.observable(data.Location);
this.ShiftStart = ko.observable(data.ShiftStart);
this.ShiftEnd = ko.observable(data.ShiftEnd);
this.EmployeeRoles = ko.observableArray(data.EmployeeRoles);

this.Location.subscribe(function (branchId) {
    $.ajax({
        type: "POST",
        url: SERVER_PATH + '/WebServices/AttributeService.asmx/GetDataOnLocationChange',
        data: "{" + "clientId: '" + CLIENT_ID
                    + "', unitId: '" + branchId
                    + "', effectiveDate:'" + EFFECTIVE_DATE
                    + "'}",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function (res) {
            var d = JSON.parse(res.d);
            self.EmployeeRoles(d.Roles);

            var tasks = self.Parent().WorkSegments();
            //Requirement: for any day of the week, if there is more than one work segment
            //at different branches the required type should be set to 'On' and made disable
            if (tasks.length > 1) {
                for (var i = 0; i < tasks.length; i++) {
                    if ((d.IsSection == false && tasks[i].Location() != self.Location()) || (d.IsSection == true && self.ParentBranch() != tasks[i].ParentBranch())) {
                        self.Parent().Required('O');
                    }
                    else {
                        self.Parent().Required('E');
                    }
                }
            }
        },
        error: HandleLocationChangeError
    });
}.bind(this));

this.Role = ko.observable(data.Role);
}

这里发生的是,在 DailyItems() 中可观察到的 Location() 是下拉列表中的一个值,该下拉列表通过主视图模型填充。当位置改变时,它应该根据选择的位置改变 EmployeeRoles() observablearray,因此 Location.Subscribe 方法。

我的问题是即使在初始数据加载期间也会调用此订阅方法。所以一开始就对服务器进行了不必要的调用。我只希望在用户实际更改下拉选择时调用它。

我有什么选择来实现这个目标?

问候, 查图

【问题讨论】:

  • 我没有看到它在初始加载中被调用。我错过了一些代码吗?这是我根据您提供的内容创建的小提琴。 jsfiddle.net/sujesharukil/ywEP2

标签: knockout.js viewmodel subscribe


【解决方案1】:

将数据传递到 WorkShift 构造函数是触发可观察位置上的更改事件的原因。一种方法是将 .subscribe 调用移至父对象构造子对象并且可观察对象具有其初始值之后。

您的 Add 函数将如下所示:

this.Add = function () {
    var data = {
        // SNIP
    };
    var child = new WorkShift(p, data);

    child.subscribe(function (branchId) {
        $.ajax({ 
            // SNIP       
            });
    }.bind(child)); // <--- important to use child and not 'this'!!!

    this.WorkSegments.push(child);
};

由于您已将 this 上下文绑定到子级,因此您还必须在 ajax 调用中使用“this”而不是“self”。

【讨论】:

  • 感谢您的回答,像这样处理订阅调用不会针对现有的 WorkShift() 对象注册它,不是吗?另外,如果我对 WorkShift 对象进行 subscribe 调用,它是如何在位置更改时触发的?
  • @chathuranganiePathirage 这个解决方案在另一个项目中对我有用。试一试,让我知道它是否适合你。
【解决方案2】:

以下是我的 UI 绑定:

<tbody data-bind="foreach: WorkSegments">
                                            <tr>
                                                <td class="formFields">

                                                   ct class="combobox" data-bind="options:$root.WorkLocations, value:Location, optionsText: 'Name', optionsValue: 'ID', enable: LocationActive"

                                                        style="font-size: x-small; font-style: normal; font-family: Tahoma; width: 80px">
                                                    </select>
                                                </td>
                                            </tr>
                                        </tbody>

这里的下拉选项是从主视图模型中设置的。之后,选定的元素被绑定。之后,当我在初始加载时调试代码时,会调用 Location subscribe 方法。

【讨论】:

    【解决方案3】:

    如果是第一次更改,是否可以像不运行 AJAX 调用一样简单?它不漂亮,但很简单:

    var locationInitialized = false;
    this.Location.subscribe(function (branchId) {
        if (!locationInitialized) {
             locationInitialized = true;
             return;
        }
        $.ajax({
        ...
    

    当然,你也可以在初始人口成功函数中设置locationInitialized。

    或者,设置函数,但在初始填充完成之前不要订阅它。 @explunit 展示了一种方法。

    【讨论】:

      猜你喜欢
      • 2013-12-04
      • 2013-11-17
      • 1970-01-01
      • 2012-09-20
      • 2016-02-29
      • 1970-01-01
      • 1970-01-01
      • 2015-01-04
      • 2012-10-09
      相关资源
      最近更新 更多