Статьи

Как выполнить двустороннюю привязку мобильного переключателя jQuery к переменной Knockout.js

В настоящее время я создаю мобильное приложение JavaScript и хочу отобразить Да / Нет в виде переключателя с помощью jQuery Mobile. Чтобы отследить состояние переменной и передать ее логике приложения, я использую Knockout.js .

flipswitch

Две библиотеки хорошо играют вместе, если вы обновляете переменную только в одном направлении, от пользовательского интерфейса до модели представления — в этом случае так же, как если бы Knockout не было в миксе, и аннотируйте элемент select, который используется jQuery Mobile в качестве базы для переключателя с атрибутом data-role = «slider» .

<select data-bind="options: ['Yes','No'], value: Partecipating" data-role="slider">
</select>

<script type="text/javascript">
viewModel = {
    Partecipating: ko.observable('Yes'),
};

ko.applyBindings(viewModel);
</script>

Вы можете просмотреть работу переключателя на следующем jsfiddle: http://jsfiddle.net/simonech/4HPVm/3/

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

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

Knockout.js — это JavaScript-библиотека MVVM с двусторонним связыванием, которая автоматически обновляет компоненты HTML, как только изменяется связанная с ними переменная.

jQuery Mobile «улучшает» стандартные компоненты HTML, чтобы сделать их мобильными, и это делается во время первого рендеринга HTML-страницы.

Если вы опытный фронтенд-разработчик, вы, возможно, уже понимаете, почему эти две библиотеки не могут хорошо работать вместе: jQuery Mobile «обрабатывает» DOM только один раз — в начале жизни страницы — настолько «улучшенный» HTML компоненты не могут быть обновлены простым изменением их резервной переменной, потому что Knockout.js не знает, как обновить новый пользовательский интерфейс, сгенерированный jQuery Mobile.

Нокаут пользовательские привязки к спасению

К счастью, Knockout.js является расширяемым и может быть настроен так, чтобы «научиться» обновлять пользовательские элементы пользовательского интерфейса путем указания пользовательских привязок .

Настраиваемая привязка определяет, как инициализировать и как обновить данный элемент HTML. В этом посте я покажу, как создать собственную привязку, специфичную для этой проблемы. Для получения дополнительной информации и лучшего объяснения всех деталей пользовательских привязок, пожалуйста, обратитесь к сайту документации Knockout.js .

Сначала я покажу вам код, а затем прокомментирую его. Вы также можете просмотреть рабочую демонстрацию на более полной jsFiddle: http://jsfiddle.net/simonech/EkAmv/10/

ko.bindingHandlers.jqSlider = {
    init: function(element, valueAccessor, allBindingsAccessor) {
        var currentValue = valueAccessor();
        var bindings = allBindingsAccessor();
        if(bindings.options==undefined){
            $(element).slider(currentValue);
        }
        else{
            var called=0;
            bindings.optionsAfterRender = function(option, item){
                called++;
                if(called==2)
                    $(element).slider(currentValue);
            };
        }

    },
    update: function(element) {
        $( element ).slider( "refresh" );
    }
};

Начнем с метода обновления привязки. Это вызывается каждый раз, когда HTML-компонент должен быть обновлен, и просто принудительно обновляет элемент переключателя , вызывая мобильный API jQuery.

Метод init немного сложнее, потому что он обрабатывает два сценария:

  • Первый сценарий — это когда параметры для элемента select задаются «обычно» с помощью тега option (и привязка параметров не указывается). В этом случае перекидной переключатель создается сразу после вызова метода .slider.
  • Второй сценарий — это когда параметры также поступают из модели представления и задаются через привязку параметров . В этом случае мне нужно было указать обратный вызов (путем установки привязки optionsAfterRender), который выполняется после рендеринга каждого параметра, и вызывать метод .slider только после того, как последний параметр был представлен в DOM.

Здесь применяется HTML-элемент с пользовательской привязкой:

<select data-bind="options: ['Yes','No'], value: Partecipating, jqSlider: { mini: true }" >
</select>

В качестве параметра пользовательской привязки jqSlider вы можете указать любой из параметров метода .slider, например mini , theme и trackTheme .

Отключение поведения jQuery Mobile по умолчанию для отдельных элементов

Это еще не все: jQuery mobile расширяет каждый элемент select на странице, поэтому нам нужно изменить селектор по умолчанию, используемый для поиска всех выбранных элементов на странице. Для этого нам нужно переопределить initSelector для компонента selectmenu :

$( document ).on( "mobileinit", function() {
  $.mobile.selectmenu.prototype.options.initSelector = ".mobileSelect";
});

Помните, что эти строки должны быть расположены вверху страницы, даже до включения библиотеки jQuery Mobile

Полная демонстрация

Вы также можете посмотреть демоверсию этого jsFiddle: http://jsfiddle.net/simonech/EkAmv/10/.