淘汰赛事火灾两次

时间:2014-06-30 12:19:10

标签: javascript jquery knockout.js

在我的MVC应用程序中通过以下方式创建多个Dropdown:

<select data-bind="options: findGroup(1).items(),
                        optionsText: 'country',
                        optionsValue: 'id',
                        value: selectedItem(1),
                        event: { change: selectionChange }"></select>

findgroup(x)和selectedItem(x)是我的ViewModel中的全局函数,而所有下拉列表都是相同的。

selectedItem(x)应返回当前所选的下拉选项。 selectedItem(x)是一个返回计算出的挖掘可观察量的函数。

现在我面临的问题是,selectionChange事件被触发了两次。看一下这个小提琴的例子:http://jsfiddle.net/LGveR/20/ 在此示例中,如果更改“下拉”框的值,则可以看到selectionCahnge事件被触发两次。

当我保留值:selectedItem(x)out(因此代码中没有计算函数)时它不会:参见:http://jsfiddle.net/LGveR/21/

我认为第二次触发事件来自于计算函数selectedItem(x)中的可观察事实

grp.selectedItem(grp.findItemByValue(value));

已设置。 如何防止这个可观察的设置导致“改变”事件?

TIA, 保罗

HTML:

   <select data-bind="options: findGroup(1).items(),
                        optionsText: 'country',
                        optionsValue: 'id',
                        value: selectedItem(1),
                        event: { change: selectionChange }"></select> <span data-bind="text: 'aantal: ' + findGroup(1).items().length"></span>

<br /> <span data-bind="text: 'Group Selected Country: ' + findGroup(1).selectedItem().country"></span>

<br /> <span data-bind="text: 'Computed Selected Country: ' + selectedItem(1)().country"></span>

<br /> <span data-bind="text: 'after select: ' + counter()"></span>

<br />

使用Javascript:

 var group = function (id) {
     this.id = id;
     this.items = ko.observableArray() || {};
     this.selectedItem = ko.observable();
     this.addItem = function (data) {
         this.items.push(data);
     };
     this.findItemByValue = function (id) {
         return ko.utils.arrayFirst(this.items(), function (item) {
             return item.id === id;
         });
     }
 };


 var grpItem = function (id, country) {
     this.id = id;
     this.country = country;
 };



 var ViewModel = function () {
     this.groups = ko.observableArray() || {};


     this.counter = ko.observable(0);
     this.selectionChange = function (data, event, selector, item) {

         this.counter(this.counter() + 1);
     };

     this.addGrp = function (data) {
         this.groups.push(data);
     };

     this.findGroup = function (groupId) {
         var ret = ko.utils.arrayFirst(this.groups(), function (c) {
             return c.id === groupId;
         });
         return ret;
     };

     this.selectedItem = function (groupId) {
         var grp = this.findGroup(groupId);
         return ko.computed({
             read: function () {
                 return this.findGroup(groupId).selectedItem();
             },
             write: function (value) {
                 grp.selectedItem(grp.findItemByValue(value));
             }
         }, this);
     };
 };

 var vm = new ViewModel();
 var p = new group(1);
 var a = new grpItem(1, 'holland');
 var b = new grpItem(2, 'germany');
 var c = new grpItem(3, 'brasil');
 p.addItem(a);
 p.addItem(b);
 p.addItem(c);

 vm.addGrp(p);


 ko.applyBindings(vm);

1 个答案:

答案 0 :(得分:1)

你在代码中做了几件奇怪的事情,这导致计算机重新计算了很多次。基本上,你通过设置一个具有依赖于observable的函数的observable来设置计算值,该函数重新计算你的计算(或者像那样疯狂的东西,参见http://jsfiddle.net/LGveR/25/以查看读取和写入的次数是多少次)。您可以通过几种简单的方法简化并解决此问题:

  1. 从select data-bind中删除optionsValue。这将设置 可观察数组中整个项的值(而不是 只是id)。然后,您可以简化计算的写入功能。

        <select data-bind="options: findGroup(1).items(),
                           optionsText: 'country',
                           value: selectedItem(1),
                           event: { change: selectionChange }"></select>
    

    this.selectedItem = function (groupId) {
         var grp = this.findGroup(groupId);
         return ko.computed({
             read: function () {
                 return grp.selectedItem();
             },
             write: function (value) {
                 grp.selectedItem(value);
             }
         }, this);
     };
    

    请参阅http://jsfiddle.net/LGveR/23/

  2. 或者,您可以删除viewmodel上的selectedItem 完全,并删除optionsValue(如在#1中)。然后,您只需要具有以下html的组observable:

        <select data-bind="options: findGroup(1).items(),
                            optionsText: 'country',
                            value: findGroup(1).selectedItem,
                            event: { change: selectionChange }"></select> 
        <span data-bind="text: 'aantal: ' + findGroup(1).items().length"></span>        
        <br /> 
        <span data-bind="text: 'Group Selected Country: ' + findGroup(1).selectedItem().country"></span>
        ...
    

    请参阅http://jsfiddle.net/LGveR/24/