KO绑定值与下拉列表不同步

时间:2017-08-01 11:48:28

标签: knockout.js

我遇到这种情况,当从可计算的KO属性更改下拉列表时,下拉列表的绑定值observable不会自动同步。 这有点棘手,因为下拉列表是从另一个下拉列表中选择的值填充的,但为了使这一点更加清晰,我创建了这个测试小提琴来演示问题:https://jsfiddle.net/n3wjack/gzmb792p/

以下是如何模拟问题:

  • 在宠物下拉菜单中,选择约翰的第二只宠物“莫扎特”。您将看到“选定的宠物”标签更新。
  • 现在在第一个下拉列表中选择Jane。第二次下拉列表将更新,显示Jane的宠物。

所选宠物标签未更新以显示Jane的第一只宠物的名称。 如果您对宠物下拉列表进行更改,则会再次更新该值。 我不能保证用户会这样做,所以我不确定该值是否正确。

那么如何解决这个问题,或者我做错了什么?

-

我还包括下面的代码,显然这是必需的。

JS:

var petOwners = [
    { name: "John", pets: ["Blacky","Mozart"] },
  { name: "Jane", pets: ["Polly", "Felix"]}
];

var viewModel = {

  availableOwners: ko.observableArray(petOwners),
  selectedOwner: ko.observable(),  

  selectedPet: ko.observable()
}

viewModel.availablePets = ko.computed(function(){
    console.log("** availablePets computed **")
    var result = [];
    if (viewModel.selectedOwner())
    {
        console.log(viewModel.selectedOwner());
        result = viewModel.selectedOwner().pets;      
    }

    console.log(result);
    return result;
  }, this);

viewModel.peekPet = function (){
    document.getElementById("peekoutput").innerHTML += "selectedPet = " + viewModel.selectedPet.peek() + "</br>";
}

ko.applyBindings(viewModel);

HTML:

<select data-bind="foreach:availableOwners, value:selectedOwner">
  <option data-bind="text: name, value: $data"></option>
</select>
<i>
( selected: <span data-bind="text: selectedOwner().name"></span> )
</i>

<p>
This dropdown shows the pets of the owner, selected in the above dropdown.
</p>
<select data-bind="foreach:availablePets, value: selectedPet">
  <option data-bind="text: $data, value: $data"></option>
</select>

<p>
<i> 
Selected pet: <span data-bind="text: selectedPet"></span>
</i>
</p>
<p>
The selected pet however doesn't update to be in sync with the first pet in the dropdown, when you change the owner dropdown. :(
</p>

<p>
<button data-bind="click: peekPet">Peek selected pet</button>
</p>

<code id="peekoutput">
</code>

3 个答案:

答案 0 :(得分:1)

这是一种不同的方法。宠物成为一系列物体。然后你使用选项绑定。这是小提琴。

https://jsfiddle.net/0o89pmju/22/

的javascript

var petOwners = [{
  name: "John",
  pets: ["Blacky", "Mozart"]
}, {
  name: "Jane",
  pets: ["Polly", "Felix"]
}];

function petOwner(data) {
  var self = this;
  this.name = ko.observable(data.name);
  this.selectedPet = ko.observable('');
  this.pets = ko.observableArray(data.pets);
}

function viewModel() {
  var self = this;
  this.petOwners = ko.observableArray('');
  this.selectedPetOwner = ko.observable('');
}


var vm = new viewModel();


(function($) {
  ko.applyBindings(vm); //bind the knockout model
  $.each(petOwners, function(i, item) {
    vm.petOwners.push(new petOwner(item));
  });
  console.log(ko.toJS(vm));
})(jQuery);

HTML

choose a pet owner:
<select data-bind="options: petOwners,
                       optionsText: 'name',
                       value: selectedPetOwner,
                       optionsCaption: 'Choose...'"></select>

<div data-bind="with: selectedPetOwner">
  Choose a pet:
  <select data-bind="options: pets, value: selectedPet"></select>
</div>

答案 1 :(得分:1)

您需要做的就是订阅所选所有者的更改:

 var viewModel = {
  availableOwners: ko.observableArray(petOwners),
  selectedOwner: ko.observable(),  
  selectedPet: ko.observable()
 }

 viewModel.selectedOwner.subscribe(function(){
    if(viewModel.selectedOwner().pets.length > 0) {
        viewModel.selectedPet(viewModel.selectedOwner().pets[0]);
    }
 });

UPDATED JSFIDDLE

还有一个替代绑定选项,用于将所选内容与没有订阅的集合同步:

<select data-bind="options: availablePets, optionsText: $data, optionsValue: $data, value: selectedPet"></select>

https://jsfiddle.net/gzmb792p/18/

答案 2 :(得分:0)

这是因为当它刷新列表时,你没有选择任何宠物。默认情况下,它显示第一个,但并不意味着他被选中。

您可以添加指令以实际选择列表中的第一个:

viewModel.availablePets = ko.computed(function(){
   console.log("** availablePets computed **")
   var result = [];

   if (viewModel.selectedOwner())
   {
      console.log(viewModel.selectedOwner());
      result = viewModel.selectedOwner().pets;

      //something like this to mark your first pet as selected. 
      viewModel.selectedPet(result[0]);    
   }

   console.log(result);
   return result;
}, this);