【问题标题】:Knockout Event Fires twice淘汰赛事件触发两次
【发布时间】:2014-07-01 03:21:59
【问题描述】:

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

<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/ 在这个例子中,如果你改变 Dropdown 框的值,你可以看到 selectionCahnge 事件被触发了两次。

当我离开值时: selectedItem(x) 出来(因此代码中没有计算函数)它没有:见:http://jsfiddle.net/LGveR/21/

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

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

已设置。 如何防止这个 observable 的设置导致“更改”事件?

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

【问题讨论】:

  • 我在你的代码中看不到任何计算函数
  • @Jeroen,我将添加代码以供将来使用。不幸的是,在我的小提琴(Chrome)中,我在控制台中没有遇到错误:S...
  • @johnSmith ,第二个小提琴没有计算,以证明数据绑定值: selectedItem(x) “损坏”代码..

标签: javascript jquery knockout.js


【解决方案1】:

您在代码中做了一些奇怪的事情,导致计算结果被重新计算了很多次。基本上,您通过使用依赖于该 observable 的函数设置 observable 来设置计算值,该函数会重新计算您的计算值(或类似疯狂的东西,请参阅http://jsfiddle.net/LGveR/25/ 以查看读取和写入调用的次数)。有几种简单的方法可以简化和消除此问题:

  1. 从您选择的数据绑定中删除 optionsValue。这将设置 可观察数组中整个项目的值(而不是 只是身份证)。然后您可以简化计算的写入函数。

        <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. 或者,您可以删除视图模型上的 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/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-27
    • 1970-01-01
    相关资源
    最近更新 更多