javascript ko.Computed() 没有用 observableArray 更新
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19640117/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ko.Computed() is not updating with observableArray
提问by Scott
I have the following code:
我有以下代码:
// First we define our gift class, which has 2 properties:
// a Title and a Price.
// We use knockout js validation to ensure that the values input are suitable/
function Gift(item)
{
var self = this;
self.Title = ko.observable(item.Title);
// attach some validation to the Title property courtesy of knockout js validation
self.Title.extend({
required: true,
minLength: 3,
pattern: {
message: 'At least ',
params: '^[a-zA-Z]+\s?[a-zA-Z]*'
}
});
self.Price = ko.observable(item.Price);
self.Price.extend({required:true,number:true,min:0.1,max:1000});
};
var viewModelForTemplated =
{
gifts: ko.observableArray(), // gifts will be an array of Gift classes
addGift: function ()
{
this.gifts.push(new Gift({ Title: "", Price: "" }));
},
removeGift: function (gift)
{
this.gifts.remove(gift);
},
totalCost: ko.computed(function () {
if (typeof gifts == 'undefined')
return 0;
var total = 0;
for (var i = 0; i < gifts().length; i++)
{
total += parseFloat(gifts()[i].Price());
};
return total;
})
}
$(document).ready(function ()
{
// load in the data from our MVC controller
$.getJSON("gift/getdata", function (allGifts)
{
var mappedgifts = $.map(allGifts, function (gift)
{
return new Gift(gift);
});
viewModelForTemplated.gifts(mappedgifts);
});
ko.applyBindings(viewModelForTemplated, $('#templated')[0]);
}
and then (above the script)
然后(在脚本上方)
<div id="templated">
<table >
<tbody data-bind="template: { name: 'giftRowTemplate', foreach: gifts }"></tbody>
</table>
<script type="text/html" id="giftRowTemplate">
<tr>
<td>Gift name: <input data-bind="value: Title"/></td>
<td>Price: $ <input data-bind="value: Price"/></td>
<td><a href="#" data-bind="click: function() { viewModelForTemplated.removeGift($data) }">Delete</a></td>
</tr>
</script>
<p>Total Cost <span data-bind="text: totalCost"></span> </p>
<button data-bind="click: addGift">Add Gift</button>
<button data-bind="click: save">Save</button>
</div>
The totalCost method only runs once, when the gifts array is empty, and I can push or remove items onto the observableArray() no problem but nothing fires .
totalCost 方法只运行一次,当礼物数组为空时,我可以将项目推送或删除到 observableArray() 没有问题,但没有任何问题。
How do I get the span referring to totalCost to update? I bet it's something simple :)
如何获取引用 totalCost 的跨度来更新?我敢打赌这很简单:)
Thanks for your help.
谢谢你的帮助。
采纳答案by Adam Rackis
You need to unwrap your observable:
你需要解开你的可观察对象:
totalCost: ko.computed(function () {
//also, you forgot typeof below
if (typeof gifts == 'undefined')
return 0;
var total = 0; //here \/
for (var i=0; i < gifts().length; i++)
{ //and here \/
total += parseFloat(gifts()[i].Price());
};
return total;
})
The reason it's not updating, is because
它不更新的原因是因为
gifts.length
is always evaluating to 0
, and never entering the loop. And even if it did,
总是对 求值0
,从不进入循环。而且即使是这样,
gifts[i].Price()
would not work for the same reason; you need to unwrap the observable.
不会因为同样的原因而工作;您需要解开可观察对象。
Note that the reason why length evaluates to zero when you don't unwrap it is because you're getting the length of the actual observable array function. All observables in Knockout are implemented as regular functions; when you don't unwrap it, you're hitting the actual function itself, not the underlying array.
请注意,当您不展开长度时,长度计算为零的原因是因为您获得了实际可观察数组函数的长度。Knockout 中的所有 observable 都是作为常规函数实现的;当你不解开它时,你正在击中实际的函数本身,而不是底层数组。
Edit,
编辑,
Also, you need to reference gifts with this.gifts
, since it's an object property. That's why this wasn't working; gifts is alwaysundefined.
此外,您需要使用 来引用礼物this.gifts
,因为它是一个对象属性。这就是为什么这不起作用;礼物总是不确定的。
That said, you also need to do some more work to get ko computeds to work from an object literal. Read here for more info:
也就是说,您还需要做更多的工作来让 ko 计算从对象文字中工作。在这里阅读更多信息:
http://dpruna.blogspot.com/2013/09/how-to-use-kocomputed-in-javascript.html
http://dpruna.blogspot.com/2013/09/how-to-use-kocomputed-in-javascript.html
Here's how I would make your view model:
这是我如何制作您的视图模型:
function Vm{
this.gifts = ko.observableArray(); // gifts will be an array of Gift classes
this.addGift = function () {
this.gifts.push(new Gift({ Title: "", Price: "" }));
};
this.removeGift = function (gift)
{
this.gifts.remove(gift);
};
this.totalCost = ko.computed(function () {
var total = 0;
for (var i = 0; i < this.gifts().length; i++)
{
total += parseFloat(this.gifts()[i].Price());
};
return total;
}, this);
}
var viewModelForTemplated = new Vm();
回答by Artem Vyshniakov
You have to unwrap observableArray
using ()
when applying indexer to it. Update totalCost
as follow:
将索引器应用于它时,您必须解开observableArray
using ()
。更新totalCost
如下:
totalCost: ko.computed(function () {
if (this.gifts == 'undefined')
return 0;
var total = 0;
for (var i=0; i<this.gifts().length;i++)
{
total += parseFloat(this.gifts()[i].Price());
};
return total;
})