Как правильно привязать и инициализировать ползунок диапазона jQuery Mobile с помощью Knockout.js?

У меня возникли проблемы с тем, чтобы ползунок диапазона JQM хорошо работал с нокаутом. Это очень простой html-код для слайдера JQM:

<input type="range" name="quantity-slider" id="quantity-slider" min="0" max="10">

Я создал в качестве образца эту нокаутирующую привязку, примененную к готовому документу:

var ViewModel = function() {
    this.quantity = ko.observable(4);
}

$(document).ready(function () {
    ko.applyBindings(new ViewModel());
});

Я прочитал в Интернете несколько сообщений от других людей, которые также обнаружили некоторые проблемы, связанные с инициализацией JQM ползунка диапазона (например, здесь: http://css.dzone.com/articles/knockoutjs-binding-helper и здесь: http://www.programico.com/1/post/2012/12/knockoutjs-jquerymobile-slider.html) и предоставить рабочее решение, каждое со своей собственной реализацией привязки.

Один из них выглядит следующим образом (от http://www.hughanderson.com/):

data-bind="value: quantity, slider: quantity"

Все идет нормально. После этого я столкнулся с этой проблемой:

если ползунок JQM находится на первой странице, он работает. Когда слайдер JQM находится на второй странице, он больше не работает.

Я думаю, что это проблема, связанная с этим конкретным виджетом JQM и его манипуляциями с DOM, насколько я понимаю. Чтобы лучше объяснить это, я сделал два jsFiddle, где я просто менял порядок двух страниц JQM:

  1. не работает: слайдер http://jsfiddle.net/5q38Q/ на второй странице JQM
  2. работает: слайдер http://jsfiddle.net/5q38Q/1/ на первой странице JQM

Может кто-нибудь объяснить, пожалуйста, как правильно инициализировать нокаутную привязку для ползунка JQM? Может быть, есть другой способ написать пользовательскую привязку для слайдера JQM, или нокаутирующую привязку нужно поместить в событие pagebeforeshow?

ОБНОВЛЕНИЕ: со следующим изменением ползунок отображает правильное значение и синхронизируется также с частью ввода текста:

$(document).on('pagebeforeshow', '#slider-page', function(){       
    $('#quantity-slider').val(viewModel.quantity());
    $('#quantity-slider').slider('refresh');
});

но мне интересно, нет ли лучшего решения.

По крайней мере, вместе с кастомной привязкой Варуна у меня теперь это работает очень хорошо!


person user2308978    schedule 11.05.2013    source источник


Ответы (3)


Я столкнулся с той же проблемой. Вот как я это решил. Хотя это решение не обновляет наблюдаемое при непосредственном редактировании значения с помощью ввода текста. (Я не отображаю текстовое поле ввода, поэтому мне этого решения достаточно)

http://jsfiddle.net/WMr8D/9/

$(document).ready(function () {
var ViewModel = function () {
    var self = this;
    self.quantity = ko.observable(4);
};    

ko.bindingHandlers.slider = {
    init: function (element, valueAccessor) {
        var value = valueAccessor();
        $(document).on({
            "mouseup touchend keypress": function (elem) {
                value($('#' + element.id).val());
            }
        }, ".c-slider");
    }
};    

ko.applyBindings(new ViewModel());
});
person darkphantum    schedule 12.05.2013
comment
Привет, Варун! Большое спасибо за то, что поделились своим опытом и своей работой. Но когда я пробую ваш образец, я всегда вижу одну и ту же проблему: когда я перехожу на вторую страницу, ползунок не инициализируется значением 4. Итак, вопрос, почему это происходит? - person user2308978; 13.05.2013
comment
я прочитал ваш другой пост об этой проблеме здесь: stackoverflow.com/a/16493161/2308978 Также для меня единственный рабочий индивидуальная привязка — ваша! - person user2308978; 14.05.2013
comment
Привет, Варун. Я изменил код, используя непосредственно селектор ui-slider, без оболочки c-slider, и это также сработало. Не могли бы вы обновить свой ответ и, возможно, объяснить, зачем вам нужен ко, если: есть? У меня работало и без него. Было бы здорово, если бы вы могли лучше объяснить свой опыт в этом спорном вопросе. - person user2308978; 14.05.2013
comment
Условие If имитирует добавление элемента управления позже. В вашем случае, поскольку вы просматриваете страницы, элемент управления добавляется динамически с помощью jqm. Я хотел сделать то же самое, но без нескольких страниц :) - person darkphantum; 15.05.2013

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

Последняя рабочая скрипта: http://jsfiddle.net/CT7fy/

Вопрос был о том, как интегрировать Knockout.js и слайдер JQuery Mobile с многостраничной навигацией, что, я думаю, будет одной из самых распространенных ситуаций.

Поэтому мне жаль, что я не могу считать ответ Варуна полным и удовлетворительным, но я должен сказать, что без специального обработчика привязки Варуна я бы никогда не нашел работающее решение.

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

/* custom binding handler thanks to Varun http://stackoverflow.com/a/16493161/2308978 */
ko.bindingHandlers.slider = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var value = valueAccessor();
            $(document).on({
                "mouseup touchend keypress": function (elem) {
                var sliderVal = $('#' + element.id).val();
                value(sliderVal);
            }
        }, ".ui-slider");
    }
 };

...и вот инициализация страницы:

$(document).on('pagebeforeshow', '#slider-page', function(){
    $('#quantity-slider').val(viewModel.quantity());
    $('#quantity-slider').slider('refresh');
});

Текстовая часть ползунка также синхронизируется после нажатия клавиши ввода или табуляции, так как это стандартное поведение ползунка.

person user2308978    schedule 17.05.2013

В пользовательском обработчике надежнее привязываться к событию «change», чем привязываться к касанию мыши и нажатию клавиши. Также событие pagebeforeshow не является необходимым. Вы можете просто установить атрибут value во время инициализации в обработчике:

ko.bindingHandlers.slider = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var value = valueAccessor();
        $(element).attr("value", value());
            $(document).on({
                "change": function (elem) {
                var sliderVal = $('#' + element.id).val();
                value(sliderVal);
            }
        }, ".ui-slider");
    }
 };

См. пример: http://jsfiddle.net/ZbrB7/2483/

person sliderfantastic    schedule 21.05.2014