Использование нокаута js с ползунками jquery ui
Я пытаюсь выяснить, будет ли нокаут js работать хорошо для следующей проблемы:
У меня есть несколько слайдеров, которые я хочу связать с текстовыми полями.
При изменении текстового поля соответствующий слайдер должен обновиться до нового значения и наоборот.
При изменении значения ползунка или текстового поля необходимо вызвать функцию, которая использует ввод из всех текстовых полей для вычисления результата.
У меня есть мое быстрое и грязное решение jQuery здесь.
Было бы легко добиться того же результата более элегантным способом, используя нокаут js?
Я предполагаю, что мне нужно будет создать настраиваемый обработчик привязки, как это сделано в jQuery UI datepicker change событие, которое не было обнаружено KnockoutJS
Ответы
Ответ 1
Вот пример: http://jsfiddle.net/jearles/Dt7Ka/
Я использую настраиваемую привязку для интеграции слайдера jquery-ui и использую Knockout для захвата входов и вычисления чистой суммы.
-
интерфейс
<h2>Slider Demo</h2>
Savings: <input data-bind="value: savings, valueUpdate: 'afterkeydown'" />
<div style="margin: 10px" data-bind="slider: savings, sliderOptions: {min: 0, max: 100, range: 'min', step: 1}"></div>
Spent: <input data-bind="value: spent, valueUpdate: 'afterkeydown'" />
<div style="margin: 10px" data-bind="slider: spent, sliderOptions: {min: 0, max: 100, range: 'min', step: 1}"></div>
Net: <span data-bind="text: net"></span>
Просмотр модели
ko.bindingHandlers.slider = {
init: function (element, valueAccessor, allBindingsAccessor) {
var options = allBindingsAccessor().sliderOptions || {};
$(element).slider(options);
ko.utils.registerEventHandler(element, "slidechange", function (event, ui) {
var observable = valueAccessor();
observable(ui.value);
});
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).slider("destroy");
});
ko.utils.registerEventHandler(element, "slide", function (event, ui) {
var observable = valueAccessor();
observable(ui.value);
});
},
update: function (element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
if (isNaN(value)) value = 0;
$(element).slider("value", value);
}
};
var ViewModel = function() {
var self = this;
self.savings = ko.observable(10);
self.spent = ko.observable(5);
self.net = ko.computed(function() {
return self.savings() - self.spent();
});
}
ko.applyBindings(new ViewModel());
Ответ 2
Я знаю это несколько дней назад, но я внес несколько изменений в код Джона Эрлса:
ko.bindingHandlers.slider = {
init: function (element, valueAccessor, allBindingsAccessor) {
var options = allBindingsAccessor().sliderOptions || {};
$(element).slider(options);
ko.utils.registerEventHandler(element, "slidechange", function (event, ui) {
var observable = valueAccessor();
observable(ui.value);
});
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).slider("destroy");
});
ko.utils.registerEventHandler(element, "slide", function (event, ui) {
var observable = valueAccessor();
observable(ui.value);
});
},
update: function (element, valueAccessor, allBindingsAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
if (isNaN(value)) value = 0;
$(element).slider("option", allBindingsAccessor().sliderOptions);
$(element).slider("value", value);
}
};
Причиной этого является то, что если вы используете параметры, которые меняются (fx другой наблюдаемый), то это не повлияет на слайдер, даже если вы этого захотите.
Ответ 3
@Джон Эрлс и @Майкл Кир Хансен: спасибо за ваши замечательные решения!
Я использовал расширенный код от Michael Kire Hansen. Я привязал опцию "max:" ползунка к ko.observable, и оказалось, что слайдер неправильно обновляет значение в этом случае. Пример. Предположим, что ползунок имеет значение 25 макс. 25, и вы изменяете максимальное значение до 100, ползунок остается в самом правом положении, указывая, что он находится на максимальном значении (но значение все равно 25, а не 100). Как только вы сдвинете одну точку влево, вы получите значение, обновленное до 99.
Решение:
в разделе "update:" просто переключите последние две строки на:
$(element).slider("option", allBindingsAccessor().sliderOptions);
$(element).slider("value", value);
Это сначала изменяет параметры, затем значение и работает как шарм.
Ответ 4
Большое спасибо за помощь, мне нужно было использовать слайдер диапазона в моем сценарии, поэтому здесь есть расширение для @John Earles и @Michael Kire Hansen
ko.bindingHandlers.sliderRange = {
init: function (element, valueAccessor, allBindingsAccessor) {
var options = allBindingsAccessor().sliderOptions || {};
$(element).slider(options);
ko.utils.registerEventHandler(element, "slidechange", function (event, ui) {
var observable = valueAccessor();
observable.Min(ui.values[0]);
observable.Max(ui.values[1]);
});
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).slider("destroy");
});
ko.utils.registerEventHandler(element, "slide", function (event, ui) {
var observable = valueAccessor();
observable.Min(ui.values[0]);
observable.Max(ui.values[1]);
});
},
update: function (element, valueAccessor, allBindingsAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
if (isNaN(value.Min())) value.Min(0);
if (isNaN(value.Max())) value.Max(0);
$(element).slider("option", allBindingsAccessor().sliderOptions);
$(element).slider("values", 0, value.Min());
$(element).slider("values", 1, value.Max());
}
};
а затем HTML для сопровождения
<div id="slider-range"
data-bind="sliderRange: { Min: 0, Max: 100 },
sliderOptions: {
range: true,
min: 0,
max: 100,
step: 10,
values: [0, 100]
}"></div>