Knockoutjs - потеряна двусторонняя привязка для выбора значения при использовании foreach вместо опций

У меня есть два элемента управления.

Один зависит от другого. Для простого примера предположим, что первый отображает список городов, а другой отображает список улиц в каждом городе.

Когда страница изначально загружается, элемент управления выбора, отображающий улицы, показывает все доступные улицы. Однако, как только пользователь выбирает город в первом выборе, второй выбор фильтруется для отображения улиц, принадлежащих только выбранному городу.

Это работает нормально при использовании связывания опций, однако мне нужна возможность генерации привязок optgroups и options, которая не поддерживает его, поэтому мне нужно использовать привязку foreach.

В результате получается, что всякий раз, когда выбран город, происходят два непредвиденных последствия:

  • Второй выбор (отфильтрованный список улиц), по-видимому, имеет первую улицу выбранного города, хотя я использую valueAllowUnset: true. Это не отражено в модели представления
  • Когда вы выбираете улицу во втором выборе, а затем выбираете другой город в первом выборе, второй выбирает правильно, чтобы отражать изменения в списке, но модель представления не делает этого, тем самым сохраняя ранее выбранное значение (хотя он больше не входит в список). Даже если я удалю valueAllowUnset: true из второго select, проблема все равно останется.

Есть ли способ обхода проблемы? Мне действительно нужно использовать привязку foreach вместо привязки параметров.

JSFiddle: https://jsfiddle.net/jfxovLna/13/

var ViewModel = function() {

var self = this;

var regionAndCityArray = [{
 regionName: "Europe",
 cities: [{
   cityName: "London",
   additionalUnimportantInformation: 100
 }, {
   cityName: "Paris",
   additionalUnimportantInformation: 200
 }]
}, {
 regionName: "North America",
 cities: [{
   cityName: "New York",
   additionalUnimportantInformation: 45
 }]
}];

var cityAndStreetArray = [{
 cityName: "London",
 streets: [{
   streetName: "Parker",
   streetLength: 5
 }, {
   streetName: "Macklin",
   streetLength: 10
 }, ]
}, {
  cityName: "New York",
 streets: [{
   streetName: "5th Avenue",
   streetLength: 3
 }, {
   streetName: "Park Ave",
   streetLength: 12
 }]
}, {
  cityName: "Paris",
 streets: [{
   streetName: "Rue de Turbigo",
   streetLength: 11
 }, {
   streetName: "Rue aux Ours",
   streetLength: 12
 }]
}];

var getAvailableStreets = function() {

 var availableStreets = cityAndStreetArray;

 var selectedCity = self.selectedCity();

 var selectedRegion = _.find(regionAndCityArray,
   function(region) {
     return _.find(region.cities,
       function(city) {
         return city.cityName === selectedCity;
       });
   });

 if (selectedRegion == undefined) {
   return availableStreets;
 }

 var filteredStreets = _.filter(cityAndStreetArray,
   function(city) {
     return city.cityName === selectedCity;
   });

 return filteredStreets;
}

self.availableCities = ko.observableArray(regionAndCityArray);
self.selectedCity = ko.observable();
self.availbleStreets = ko.computed(getAvailableStreets);
self.selectedStreet = ko.observable();

};
var viewModel = new ViewModel();
ko.applyBindings(viewModel);

Ответ 1

Сначала добавьте пустую опцию к вашему входу выбора.

<option value="">Select Street</option>

Теперь подпишитесь на свойство selectedCity вашей модели просмотра. Всякий раз, когда он изменяется, программно устанавливайте selectedStreet в '..

viewModel.selectedCity.subscribe(function() { 
  viewModel.selectedStreet(''); 
}, viewModel); 

Таким образом, вы можете решить обе свои проблемы.

Сделал изменения в вашей скрипке, и она работает. пытается обновить его.

Вот скрипка - https://jsfiddle.net/Shabi_669/w1vcjbjo/