Ваша проблема связана с порядком выполнения кода.Встроенный обработчик привязки KO options
и плагин jQuery Multiselect модифицируют DOM, и обработчик options
, вероятно, выполняет после функции множественного выбора, поэтому при построении меню множественного выбора нетпока нет никаких вариантов для этого подобрать.Когда вы используете setTimeout
, даже с тайм-аутом в 1 мс, функция помещается в конец стека вызовов и будет выполняться после завершения текущего цикла событий (подробнее см. здесь ), так что теперьвыполняется после завершения привязки options
.Ergo, это работает.
Однако, это не очень красиво.Никогда не стоит выполнять манипуляции с DOM внутри модели представления.Вот почему настраиваемые обработчики привязки - это вещь;легко взаимодействовать с элементами DOM и поддерживать чистоту моделей представлений. Ваш код ссылается на обработчик привязки multiselect
, но я не вижу его в вашем посте.Если мы создадим его (это не сложно), мы увидим, что мы можем заставить меню работать так, как ожидалось. Ваша первоначальная проблема заключалась в том, что вы использовали прилагаемый обработчик привязки, а также манипулировали DOM вручную.Вы должны просто придерживаться обработчика привязки, и он будет работать нормально.Тайм-ауты не нужны.
С такими фреймворками, как KO, в качестве общего практического правила вам всегда нужно только манипулировать данными в вашей модели представления.KO должен сделать тяжелую работу по обновлению пользовательского интерфейса.Поэтому, если вы хотите выбрать все элементы, подумайте о том, как это работает: существует наблюдаемый массив с именем selected
, в котором хранятся идентификаторы выбранных элементов.Поэтому, если вы хотите выбрать все элементы, вам нужно только просмотреть все доступные элементы и отправить идентификаторы в выбранный массив.KO позаботится об обновлении интерфейса для вас.Смотрите обновленный фрагмент кода.Я создал отдельную кнопку, которая вызывает функцию selectAll
, но вы, конечно, можете просто вызвать selectAll
в вашей функции инициализации, если хотите.
var selectorVM = function () {
var self = this;
self.available = ko.observableArray([]);
self.selected = ko.observableArray([]);
self.init = function () {
self.initOptions();
};
self.initOptions = function () {
self.available([
{ name: "option 1", value: 1 },
{ name: "option 2", value: 2 }
]);
};
self.selectAll = function () {
self.available().forEach(function (opt) {
if (self.selected.indexOf(opt.value) === -1) {
self.selected.push(opt.value);
}
});
}
}
var selectorVM = new selectorVM();
ko.applyBindings(selectorVM);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-multiselect/0.9.15/js/bootstrap-multiselect.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-multiselect/0.9.15/css/bootstrap-multiselect.css" rel="stylesheet"/>
<div>
<button class="btn btn-default" data-bind="click: init">Click to init dropdown, no timeout</button>
<button class="btn btn-default" data-bind="click: selectAll">Select all</button>
</div>
<div>
<select id="selector"
class="form-control"
multiple="multiple"
data-bind="options: available,
optionsText: 'name',
optionsValue: 'value',
selectedOptions: selected,
multiselect: { includeSelectAllOption: true }">
</select>
</div>
<p>Selected options in observable array:</p>
<ul data-bind="foreach: selected"><li data-bind="text: $data"></li></ul>