敲门订阅的问题

时间:2013-03-18 04:02:12

标签: knockout.js viewmodel subscribe

地狱全部,

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

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方法。

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

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

此致 Chathu

3 个答案:

答案 0 :(得分:1)

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

您的添加功能将如下所示:

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);
};

然后你还必须在ajax调用中使用“this”而不是“self”,因为你已经将这个上下文绑定到了child。

答案 1 :(得分:0)

以下是我的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方法。

答案 2 :(得分:0)

如果是第一次更改,它可能就像没有运行AJAX调用一样简单吗?它不漂亮,但很简单:

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

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

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