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

Knockout.js KO绑定值与下拉列表不同步,knockout.js,Knockout.js,我遇到了这样的情况,当下拉列表从可计算属性更改时,下拉列表的可观察的绑定值不会自动同步。 这有点棘手,因为下拉列表是从另一个下拉列表中选择的值填充的,但为了更清楚地说明这一点,我创建了这个测试提琴,它演示了问题: 以下是如何模拟问题: 在宠物下拉列表中,选择约翰的第二只宠物“莫扎特”。您将看到“选定宠物”标签更新 现在在第一个下拉列表中选择Jane。第二个下拉列表将更新,显示Jane的宠物 所选宠物标签未更新,以显示Jane的第一只宠物的名字。 如果对“宠物”下拉列表进行更改,该值将再次更新

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

以下是如何模拟问题:

  • 在宠物下拉列表中,选择约翰的第二只宠物“莫扎特”。您将看到“选定宠物”标签更新
  • 现在在第一个下拉列表中选择Jane。第二个下拉列表将更新,显示Jane的宠物
所选宠物标签未更新,以显示Jane的第一只宠物的名字。 如果对“宠物”下拉列表进行更改,该值将再次更新。 我不能保证用户会这样做,所以我不确定该值是否正确

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

--

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

JS:

var-petOwners=[
{姓名:“约翰”,宠物:[“布莱克”,“莫扎特”]},
{姓名:“简”,宠物:[“波利”,“菲利克斯”]}
];
var viewModel={
可用所有者:ko.observableArray(宠物所有者),
已选择所有者:ko.observable(),
selectedPet:ko.observable()
}
viewModel.availablePets=ko.computed(函数(){
console.log(“**availablePets computed**”)
var结果=[];
如果(viewModel.selectedOwner())
{
log(viewModel.selectedOwner());
结果=viewModel.selectedOwner().pets;
}
控制台日志(结果);
返回结果;
},这个);
viewModel.peekPet=函数(){
document.getElementById(“peekoutput”).innerHTML++=“selectedPet=“+viewModel.selectedPet.peek()+”
”; } 应用绑定(视图模型);
HTML:


(选定:)

此下拉列表显示在上述下拉列表中选择的主人的宠物。

选定宠物:

但是,当您更改“所有者”下拉列表时,选定的宠物不会更新为与下拉列表中的第一只宠物同步(

Peek精选宠物


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

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

viewModel.availablePets=ko.computed(函数(){
console.log(“**availablePets computed**”)
var结果=[];
如果(viewModel.selectedOwner())
{
log(viewModel.selectedOwner());
结果=viewModel.selectedOwner().pets;
//类似这样的东西来标记你的第一只宠物被选中。
viewModel.selectedPet(结果[0]);
}
控制台日志(结果);
返回结果;
},这个);

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

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

viewModel.availablePets=ko.computed(函数(){
console.log(“**availablePets computed**”)
var结果=[];
如果(viewModel.selectedOwner())
{
log(viewModel.selectedOwner());
结果=viewModel.selectedOwner().pets;
//类似这样的东西来标记你的第一只宠物被选中。
viewModel.selectedPet(结果[0]);
}
控制台日志(结果);
返回结果;
},这个);

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

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

选择宠物主人:
选择宠物:

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

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

选择宠物主人:
选择宠物:

您只需订阅所选所有者的更改:

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

select还有一个替代绑定,用于将所选内容与集合同步,而无需订阅:

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


您只需订阅所选所有者的更改:

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

select还有一个替代绑定,用于将所选内容与集合同步,而无需订阅:

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


您应该使用
选项
绑定,而不是
foreach
。您应该使用
选项
绑定,而不是
foreach
。您也尝试过了,但奇怪的是它不起作用。我更新了小提琴,您甚至可以在日志中看到它设置了值,但绑定没有更新:这可能不起作用因为它拒绝将选定的宠物设置为甚至不是选项的设置,因为在返回结果之前,可用的宠物不会更新。这是有道理的。我也在想这一点。它似乎确实拒绝了编辑。也尝试过了,但奇怪的是,它不起作用。我更新了小提琴,你甚至可以使用它在日志中,它设置了值,但绑定没有更新:这可能不起作用,因为它拒绝将所选宠物设置为甚至还不是选项的内容,因为在返回结果之前,可用宠物不会更新。这是有道理的。我也在想这一点。它似乎确实拒绝了编辑。我们设置选项绑定确实有效。很有趣。我习惯于使用foreach语法,但显然KO的行为与使用选项绑定时有所不同。我想这就是它的目的。foreach只要保持简单就可以工作。但是在我的例子中,第二个下拉菜单依赖于第一个,出现了问题。使用options绑定确实有效。很有趣。我习惯于使用foreach语法,但显然KO的行为与使用选项绑定时有所不同。我猜这就是原因