为什么将一个计算器添加到observableArray会失败?

时间:2013-10-07 10:25:13

标签: knockout.js knockout-mapping-plugin

我觉得这里有些不对劲。我想像ko.computed这样添加ko.observableArray

在此之前我的模型是为了清晰

//var job = @Html.Raw(Json.Encode(Model.job));
//var customer = @Html.Raw(Json.Encode(Model.customer));
//var estimateMaterials = @Html.Raw(Json.Encode(Model.estimateMaterials));
//var estimate = @Html.Raw(Json.Encode(Model.estimate));
var estimateTasks = @Html.Raw(Json.Encode(Model.Tasks));

var JobPostViewModel = function(){
    var self = this;
    //self.customer = ko.observable(customer);
    //self.job = ko.observable(job);
    //self.estimateMaterials = ko.observableArray(estimateMaterials);
    //self.estimate = ko.observable(estimate);
    self.estimateTasks = ko.observableArray(estimateTasks);
    self.estimateTasks().estLaborSubTotal = ko.computed(function () {
        return (isNaN(self.EstHr)? 0: +self.EstHr) * (isNaN(self.TaskPerHourCost)? 0: +self.TaskPerHourCost);
    });
};
var model = new JobPostViewModel();
ko.applyBindings(model,  document.getElementById("my_job_form"));

所以这就是我的模型绑定。 my_job_formdata-bind="with:jobs",我正在填充绑定到estimateTasks的表单中的表。标记是

<tbody data-bind="foreach: $root.estimateTasks">
    <tr>
        <td>
            <input type="text" data-bind="value: EstHr" />
            <input type="hidden" data-bind="value: TaskPerHourCost" />
        </td>
        <td>
            <input type="text" data-bind="value: estLaborSubTotal" disabled />
        </td>
    </tr>
</tbody>

在绑定时,我收到错误

  

ReferenceError:未定义estLaborSubTotal

我在这里做错了什么?

3 个答案:

答案 0 :(得分:3)

您正在向数组添加计算器。这个数组只是对estimateTasks observableArray();

的评估结果

如果我理解你想要做什么。

你最好这样做。 这将为项目添加一个名为estLaborSubTotal的计算。

var JobPostViewModel = function(){
    var self = this;
    ko.utils.arrayForEach(estimateTasks, function(et) {
        et.estLaborSubTotal  = ko.computed({
            read: function(){
                var estHr = this.EstHr();
                var taskPerHourCost =  this.TaskPerHourCost();
                if(estHr === null)
                    return 0;
                return estHr * taskPerHourCost; 
            },
            owner : et // specify the "this" during evaluation 
        });
    });

    self.estimateTasks = ko.observableArray(estimateTasks);
};

See fiddle

我希望它有所帮助。

答案 1 :(得分:2)

我认为这就是你要做的事情 -

function jobPostEstimateTaskModel (task) {
    var self = this;
    // Make some properties of this task observable
    self.name = ko.observable(task.name);
    // Make a computed for each task
    self.estLaborSubTotal = ko.computed(function () {
        return (isNaN(self.EstHr)? 0: +self.EstHr) * (isNaN(self.TaskPerHourCost)? 0: +self.TaskPerHourCost);
    });
}

var JobPostViewModel = function(){
    var self = this;
    self.estimateTasks = ko.observableArray();
    $.each(estimateTasks, function (index, item) {
        self.estimateTasks.push(new jobPostEstimateTaskModel(item));
    }
};

这将遍历您创建的estimateTasks普通旧JavaScript数组,并为数组中的每个任务添加一个新的jobPostEstimateTaskModel对象。它将在任务中创建可观察的属性,例如本例中的name,然后为数组中的每个项创建一个计算。

通过以上面的方式调用它,你只需在observableArray上创建一个计算器,而不是按照你的意图。

其中一个混淆点是你的ViewModel有一个名为estimateTasks的observableArray对象,但你在上面的上下文中也有一个变量,它命名完全相同。考虑将不可观察的内容重命名为estimateTasksJson以澄清。

修改

另一种解决方法是使用原型 - 您仍然需要实例化一个像jobPostEstimateTaskModel这样的对象或者你想要调用它的任何东西,但是你可以将一个observable扩展到每个实例上,而不必每次迭代该代码并添加它在模型中。

答案 2 :(得分:1)

您的问题是foreach内部当前绑定内容是当前数组元素 此元素没有estLaborSubTotal属性 您可以改为使用<input type="text" data-bind="value: $root.estimateTasks().estLaborSubTotal" disabled />

或者您可以更改您的viewmodel:

var JobPostViewModel = function(){
    var self = this;
    //self.customer = ko.observable(customer);
    //self.job = ko.observable(job);
    //self.estimateMaterials = ko.observableArray(estimateMaterials);
    //self.estimate = ko.observable(estimate);
    self.estimateTasks = ko.observableArray(estimateTasks);
    self.estLaborSubTotal = ko.computed(function () {
        return (isNaN(self.EstHr)? 0: +self.EstHr) * (isNaN(self.TaskPerHourCost)? 0: +self.TaskPerHourCost);
    });
};

并使用<input type="text" data-bind="value: $root.estLaborSubTotal" disabled />