Привязка нокаута после выбора рендера

Итак, у меня есть Select, у которого есть свои параметры из вычисленного. Я хочу выбирать значение по умолчанию каждый раз, когда меняются параметры выбора.

Я пробовал несколько разных способов сделать это:

  • подписаться на список - вызывается до того, как список вернется, поэтому изменяет значение наблюдаемого в порядке, но он не отображается правильно, потому что список изменяется ПОСЛЕ.

  • afterRender — не работает с этим типом привязки.

  • OptionsafterRender - работает, как и в скрипте ниже, ОДНАКО он вызывается для каждого отдельного элемента, а не только один раз для всего рендеринга, поэтому мне кажется, что это неправильный способ сделать это.

var rawData = [{
  Type: "1",
  Color: "Blue",
  Name: "Blue Car"
}, {
  Type: "2",
  Color: "Blue",
  Name: "Blue House"
}, {
  Type: "1",
  Color: "Red",
  Name: "Red Car"
}, {
  Type: "2",
  Color: "Red",
  Name: "Red House"
}];
var viewModel = {
  FirstSelectedOption: ko.observable(),
  SecondSelectOptions: null,
  SecondSelectedOption: ko.observable(),
  Load: function() {
    var self = viewModel;
    self.SecondSelectOptions = ko.computed(function() {
      var selected = self.FirstSelectedOption();
      var returnValue = new Array({
        Type: "*",
        Color: "All",
        Name: "All"
      });
      var filteredlist = ko.utils.arrayFilter(rawData, function(item) {
        return item.Type == selected;
      });
      returnValue = returnValue.concat(filteredlist);
      return returnValue;
    }, self);
    self.SecondSelectedOption.SetDefault = function() {
      // we want the default to always be blue instead 'all', blue might not be the last option
      var self = viewModel;
      var defaultoption = ko.utils.arrayFirst(self.SecondSelectOptions(), function(item) {
        return item.Color == "Blue";
      });
      self.SecondSelectedOption(defaultoption);
    };
  }

};

viewModel.Load();
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<select data-bind="value: FirstSelectedOption">
  <option value="1">Car</option>
  <option value="2">House</option>
</select>
<br/>
<select data-bind="options: SecondSelectOptions, 
                   optionsText: 'Name',                               
                   value: SecondSelectedOption,
                   optionsAfterRender: SecondSelectedOption.SetDefault"></select>

http://jsfiddle.net/dt627rkp/

Единственный способ, который приходит мне на ум, — это пользовательская привязка... и я даже не уверен, что это действительно возможно без повторной реализации всей привязки параметров.
Я не могу быть первым, кто захочет это, есть ли лучшая практика/способ, который мне не хватает?


person Madoc    schedule 06.03.2015    source источник
comment
Вы можете создать 2 выбора для селекторов цвета. А затем показать/скрыть в зависимости от того, какой выбор сделан в селекторе автомобиля/дома...   -  person sfletche    schedule 07.03.2015
comment
Хм, это достаточно безумно, чтобы работать ... Однако я не уверен, что мне это нравится, потому что данные на самом деле загружаются динамически, и их много, поэтому мне пришлось бы динамически добавлять их в дом, когда другие параметры на первом селектор выбран, но не невозможен. Очевидно, что фрагмент не является моим фактическим кодом, он НАМНОГО упрощен. Спасибо.   -  person Madoc    schedule 07.03.2015


Ответы (1)


Обратный вызов optionsAfterRender передает 2 параметра: параметр (элемент) и элемент (данные, привязанные к параметру). Обратный вызов уже зацикливается на параметрах, поэтому нет необходимости повторять:

self.SecondSelectedOption.SetDefault = function (option, item) {
   var self = viewModel;
   if (item.Color === 'Blue')
       self.SecondSelectedOption(item);
};

Обновленная скрипта
Ссылка: из документов

РЕДАКТИРОВАТЬ: При этом, если вы не хотите, чтобы параметры переоценивались каждый раз, вы также можете просто связать событие change с методом setDefault для первого <select>. Если бы я столкнулся с этой «проблемой» кода, я бы, вероятно, предварительно обработал данные в отдельные массивы, как в этом скрипка

person Tyblitz    schedule 06.03.2015
comment
Ба, почему я не подумал об этом. По-прежнему означает, что он вызывается каждый раз, когда элемент добавляется в список, что может быть много для больших списков, но вы, по крайней мере, устранили цикл, поэтому я не так озабочен производительностью. И я не думаю, что можно сделать что-то лучше, не переписывая все это целиком или не создавая большую пользовательскую привязку. Спасибо! - person Madoc; 07.03.2015
comment
@Madoc, если хотите, вы также можете предварительно обработать данные в массивы. Если у вас есть возможность, я бы разделил цвет и тип свойства (которое на самом деле является «вычисляемым» свойством) и сделал бы его немного более семантическим, см. мое редактирование. - person Tyblitz; 07.03.2015
comment
@Tybiltz Завтра я попробую событие изменения, не уверен, что оно сработает в правильном порядке, это легко проверить. Я не могу разделить данные таким образом, ну, я могу, но это вызовет гораздо больше проблем, чем решит, потому что реальные данные намного сложнее, используются в большем количестве мест и даже более взаимосвязаны, чем показывает этот пример. Я написал скрипку с нуля как самую простую часть, которая отражала бы то, что я хотел сделать. У него снято много слоев. Там много вещей, которые я бы не стал делать, если бы данные были такими же простыми, как в примере. Но спасибо! - person Madoc; 07.03.2015