【问题标题】:KO bound value out of sync with dropdownKO 绑定值与下拉列表不同步
【发布时间】:2017-08-04 23:08:17
【问题描述】:

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

这是模拟问题的方法:

  • 在宠物下拉列表中,选择约翰的第二只宠物“莫扎特”。您会看到“选定宠物”标签更新。
  • 现在在第一个下拉列表中选择 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>

【问题讨论】:

  • 你应该使用options绑定而不是foreach

标签: knockout.js


【解决方案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/

【讨论】:

  • 使用选项绑定确实有效。有趣的。我习惯于使用这种 foreach 语法,但显然 KO 的行为与使用该选项绑定时的行为不同。我想这就是它的意思。只要你保持简单,foreach 就可以工作。但在我的情况下,第二个下拉菜单依赖于第一个事情出了问题。
【解决方案2】:

这是一种不同的方法。 petowners 成为一个对象数组。然后你使用选项绑定。这是小提琴。

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>

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

    • 也试过了,奇怪的是它不起作用。我更新了小提琴,你甚至可以在日志中看到它设置了值,但绑定没有更新:jsfiddle.net/n3wjack/gzmb792p/15
    • 这可能不起作用,因为它拒绝将选定的宠物设置为甚至还不是一个选项的东西,因为在返回结果之前不会更新可用的宠物。
    • 这是有道理的。我也在想这方面的事情。它似乎确实拒绝编辑。
    猜你喜欢
    • 1970-01-01
    • 2011-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-12
    相关资源
    最近更新 更多