2017-08-01 63 views
0

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

这里是如何模拟问题:

  • 在宠物下拉列表中,选择John的第二只宠物“Mozart”。你会看到'selected宠物'标签更新。
  • 现在在第一个下拉列表中选择简。第二个下拉列表将更新,显示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> 
+0

你应该使用'options'结合,而不是'的foreach '。 –

回答

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/

+0

确实使用选项绑定工作。有趣。我习惯于使用foreach语法,但显然KO的行为似乎与使用该选项绑定时不同。我想这就是它的意思。 只要你保持简单,foreach就可以工作。但在我的情况下,第一个事件出现了错误。 – n3wjack

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

也尝试过,奇怪的是它不起作用。我更新了小提琴,你甚至可以在日志中看到它设置的值,但绑定不会更新:https://jsfiddle.net/n3wjack/gzmb792p/15/ – n3wjack

+0

这可能无法正常工作,因为它拒绝设置选定的宠物,甚至没有选择,因为可用的宠物不会更新,直到返回结果。 –

+0

这很有道理。我也在思考这个问题。它似乎确实拒绝编辑。 – n3wjack

1

这里是一个不同的方法。 pet主成为一组对象。那么你使用选项绑定。这里是小提琴。

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>