Использование KnockoutJS, как создать список с несколькими вариантами выбора

#knockout.js #jquery-ui-selectable

#knockout.js #jquery-выбираемый пользовательский интерфейс

Вопрос:

Я пытаюсь использовать функциональность списка выбора jQuery при использовании KnockoutJS, но не могу заставить его работать.

Используя пользовательские привязки, мне удалось преобразовать ul элемент в выбираемый и создать обработчики событий для выбранных и невыбранных событий. Но что мне передать моим функциям ViewModel, которые поддерживают выбранные элементы?

Вот мой код до сих пор: http://jsfiddle.net/QCmJt /

Я новичок во всем этом, поэтому, возможно, я неправильно подхожу к этому…

Ответ №1:

Вот немного измененный вариант вашего, он тоже работает. Он использует свойство selected для каждого элемента в массиве, которое является наблюдаемым для двусторонней связи. Если вам нужно свойство, представляющее собой просто список выбранных элементов, вы всегда можете создать зависимую наблюдаемую или просто метод для фильтрации.

http://jsfiddle.net/QCmJt/32/

Создана пользовательская привязка:

 ko.bindingHandlers.selectableItem = {
    init: function(element, valueAccessor, allBindingsAccessor) {
        var selectable = $(element).parent();

        selectable.bind('selectableselected', function(event, ui) {
            if(ui.selected === element) {                
                var value = valueAccessor();

                value(true);
            }
        });

        selectable.bind('selectableunselected', function(event, ui) {
            if(ui.unselected === element) {                
                var value = valueAccessor();

                value(false);                
            }
        });
    },
    update: function(element, valueAccessor, allBindingsAccessor, viewModel) {
        var el = $(element);

        if(valueAccessor()()) {
            el.addClass('ui-selected');
        } else {
            el.removeClass('ui-selected');
        }
    }
};
  

Он не предназначен для более чем очень простых двухсторонних привязок, но должен быть достаточно простым в построении.

Комментарии:

1. Спасибо, Пол! Это хороший способ приблизиться к этому. Меня беспокоит только смешивание статуса выбора строки пользовательского интерфейса в свойстве модели представления «запросы». В моем сценарии свойство ‘requests’ синхронизируется обратно с серверной частью, и поэтому я предпочитаю использовать другое свойство для сохранения статуса выбранной строки.

2. @joerage Да, я знаю, что ты имеешь в виду. Я видел, как вы его представили, и попытался заставить его работать таким образом, но не повезло. Вы должны рассматривать это как MVVM, поскольку это цель Knockout. В MVVM ViewModel является абстракцией представления и гораздо более тесно связана с пользовательским интерфейсом, не обязательно с объектами вашего домена, поэтому имеет смысл, что если эти объекты пользовательского интерфейса имеют свойство, указывающее статус выбора, которое отражается в ViewModel. Если вам нужно, чтобы это представление отличалось для сохранения, вы всегда можете переназначить объекты на сервере.

Ответ №2:

Хорошо, я нашел способ передать данные, привязанные к выбранному элементу:

$(ui.selected).tmplItem().data при выборе и $(ui.selected).tmplItem().data при отмене выбора.

Вот обновленная скрипка: http://jsfiddle.net/8RnxC /

Пользовательская привязка выглядит следующим образом:

 ko.bindingHandlers.selectable = {
        init: function(element, valueAccessor) {
            $(element).attr("id", "selectable").selectable({
                selected: function(event, ui) {
                    vm.selectRequest($(ui.selected).tmplItem().data);
                },
                unselected: function(event, ui) {
                    vm.unselectRequest($(ui.unselected).tmplItem().data);
                }
            });
        }
    };
  

И моя модель представления:

 function viewModel() {
        // Data
        this.requests = ko.observableArray([]);
        this.selectedRequests = ko.observableArray([]);

        // Behaviours
        this.selectRequest = function(request) {
            this.name = "othername";
            // Add to array if not already there.
            if ($.inArray(request, this.selectedRequests()) === -1) {
                this.selectedRequests().push(request);
            }
            var self = this;

        };
        this.unselectRequest = function(request) {
            // Remove from the array.
            this.selectedRequests().splice($.inArray(request, this.selectedRequests()), 1);
        };
    };