2014-06-30 1 views
2

dans mon application MVC im la création de plusieurs Dropdowns en suivant:Event Knockout incendies deux fois

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

la findGroup (x) et le selectedItem (x) sont des fonctions globales dans mon ViewModel alors que ceux-ci sont pour tous les menus déroulants du même. L'option selectedItem (x) doit renvoyer l'option actuellement sélectionnée de la liste déroulante

. selectedItem (x) est une fonction permettant de renvoyer un knock-out calculé.

Maintenant, je suis confronté au problème que l'événement selectionChange est déclenché deux fois. Voir ce violon pour un exemple: http://jsfiddle.net/LGveR/20/ Dans cet exemple, si vous modifiez la valeur de la zone de liste déroulante, vous pouvez voir que l'événement selectionCahnge est déclenché deux fois.

Quand je laisse la valeur: selectedItem (x) sur (et donc pas de fonction calculée dans le code), il ne marche pas: voir: http://jsfiddle.net/LGveR/21/

Je pense que la deuxième fois que l'événement est tiré vient du fait que dans la fonction calculée selectedItem (x) l'observable

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

est activé. Comment empêcher que le paramétrage de cet observable mène à un événement "Change"?

TIA, Paul

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

je ne peux pas voir une fonction calculée dans votre code –

+0

@Jeroen, je vais ajouter le code pour une utilisation future. Malheureusement dans mon violon (Chrome) je ne fais face à aucune erreur dans la console: S ... – Paul

+0

@johnSmith, le deuxième violon n'a pas été calculé, pour démontrer que la valeur de liaison de données: selectedItem (x) "corrompt" le code .. – Paul

Répondre

1

Tu fais quelques choses bizarres dans votre code qui se traduit par la calculé étant recalculée un groupe de temps. Fondamentalement, vous définissez la valeur calculée en définissant un observable avec une fonction qui repose sur ce observable, qui recalcule votre calculé (ou quelque chose de fou comme ça, voir http://jsfiddle.net/LGveR/25/ pour voir combien de fois lire et écrire sont appelés). Il y a quelques façons simples que vous pouvez simplifier et à éliminer ce problème:

  1. Retirez le optionsValue de votre select-bind de données. Cela définira la valeur à l'ensemble de l'élément dans le tableau observable (au lieu de juste l'ID). Vous pouvez ensuite simplifier la fonction d'écriture calculée.

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

    et

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

    voir http://jsfiddle.net/LGveR/23/

  2. Sinon, vous pouvez retirer le selectedItem sur le viewmodel entièrement, et retirer le optionsValue (comme dans # 1)., Il vous suffit alors le groupe observable avec le code HTML suivant:

    <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> 
        ... 
    

    Voir http://jsfiddle.net/LGveR/24/

Questions connexes