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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 16:18:34  来源:igfitidea点击:

ko.Computed() is not updating with observableArray

javascriptknockout.jsupdatingko.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 observableArrayusing ()when applying indexer to it. Update totalCostas follow:

将索引器应用于它时,您必须解开observableArrayusing ()。更新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;
})