Каскадные выпадающие списки с knockout.js и select2

0

Посмотрите этот jsfiddle

Я встречаю два вопроса:

  1. Я не могу вернуть текст выбранного объекта (cascadingOption).
  2. Я проиграл, как верно перевести выпадающие списки на select2.

В частности, это:

    <select id="make" data-bind="options: carMakers, 
                                 value: selectedMake, 
                                 optionsText : 'text', 
                                 optionsCaption : 'Select your make'">
    </select><br/>
    Selected Make: <span data-bind="text: selectedMake"></span><br/>

возвращает [объект Object] на экран. Если я изменяю последнюю строку для span data-bind="text: selectedMake.text" она ничего не возвращает. Однако, если я использую subscribe от нокаута и журнал на консоль, я могу вернуть object.text в порядке?

Вторая проблема заключается в том, что я select2: { } первый тег select, добавляя select2: { } в свой атрибут привязки данных. Это правильно изменит выпадающий список на стиль select2, но все каскадные свойства разваливаются.

Любая помощь или руководство будут с благодарностью оценены.

Теги:
jquery-select2
knockout.js
cascadingdropdown

2 ответа

2
Лучший ответ

selectedMake является наблюдаемым, его значение будет каскадным экземпляром Option. Чтобы использовать это в своем диапазоне: текстовое связывание, вам понадобятся:

<span data-bind="text: selectedMake().text"></span>

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


Select2 пытается синхронизировать элемент select с его внутренним состоянием. К сожалению, он зависит от каждой опции, имеющей значение Id. Поскольку вы не используете привязки optionsValue, это не сработает. Я также использую select2, но я изменил их код, чтобы использовать optionIndex вместо Id и довольно сложную привязку select2 для управления различиями, например Ajax и multiselect.

Тем не менее, вы получаете образец, который работает с select2...

  1. Создайте наблюдаемое для хранения идентификатора.
  2. Измените привязку значения для использования идентификатора Id
  3. Добавьте привязку optionsValue, чтобы вернуть уникальный идентификатор из вашей исходной опции. Это будет использоваться для синхронизации опции select2 и опции выбора.
  4. Добавьте подписку на идентификатор, подлежащий фильтрации, чтобы отфильтровать параметры и вернуть объект из массива параметров
  5. Добавьте подписку на наблюдаемое значение, чтобы синхронизировать идентификатор (будьте осторожны с бесконечным циклом между двумя подписками)

Я обновил JSFiddle, но различия ниже. В этом случае я создаю функцию-оболочку для создания пары наблюдаемых /id с подписями между 2. Связывание выбора имеет другое значение привязки значения и добавленную привязку optionValue Связывание диапазона имеет другое значение привязки текста.

HTML

<div>
    <select id="make" data-bind="options: carMakers, value: selectedMake.id, optionsValue: 'text', optionsText : 'text', optionsCaption : 'Select your make', select2: {}"></select><br/>
    Selected Make: <span data-bind="text: selectedMake().text"></span><br/>
    <select id="type" data-bind="options: carTypes, value: selectedType.id, optionsValue: 'text', optionsText : 'text', optionsCaption : 'Select your type', enable : carTypes, select2: {}"></select><br/>
    Selected Model: <span data-bind="text: selectedType().text"></span><br/>
    <select id="model" data-bind="options: carModels, value: selectedModel.id, optionsValue: 'text', optionsText : 'text', optionsCaption : 'Select your Model', enable: carModels, select2: {}"></select><br/>
    Selected Model: <span data-bind="text: selectedModel().text"></span><br/>
</div>

Javascript

var makeObservableForSelect2 = function( sourceOptions, idSelector ) {
    var target = ko.observable({});
    target.id = ko.observable();

    target.id.subscribe( function(id) {
        var realSource = ko.unwrap(sourceOptions)
        if ( !realSource ) {
            return;
        };
        // Don't set target if id already matches to stop infinite loop.
        if ( target() && target()[idSelector] === id ) {
            return;
        }

        target( realSource.filter( function(item) { return item[idSelector] === id; } )[0] || {} );
    } );

    target.subscribe( function(value) {
        // Don't set id if id already matches to stop infinite loop.
        if ( target.id() && value[idSelector] === target.id() ) {
            return;
        }

        target.id(value[idSelector]);
    });

    return target;
};

var viewModel = {
    carMakers: buildData()
};

viewModel.selectedMake = makeObservableForSelect2( viewModel.carMakers, 'text');

viewModel.carTypes = ko.computed(function(){
    return viewModel.selectedMake() ? viewModel.selectedMake().childOptions : null;
});

viewModel.selectedType = makeObservableForSelect2( viewModel.carTypes, 'text');

viewModel.carModels = ko.computed(function(){
    return viewModel.selectedType() ? viewModel.selectedType().childOptions : null;
});

viewModel.selectedModel = makeObservableForSelect2( viewModel.carModels, 'text');
2

Рабочая скрипка: http://jsfiddle.net/jiggle/Lw2qJ/

Проблема 1:

Вы можете сделать span data-bind="text: selectedMake().text" (обратите внимание на скобки), но только если selectedMake всегда будет иметь значение (и, следовательно, имеет свойство.text).

Есть несколько других способов сделать это, которые изложены на http://www.knockmeout.net/2011/08/simplifying-and-cleaning-up-views-in.html

Проблема 2:

Однако, когда я начал изучать проблему 2, я обнаружил, что свойство optionsValue должно быть установлено, чтобы select2 работал правильно (хотя кто-то мог поправить меня по этому поводу), поэтому я немного переработал так, чтобы ваш selectedMake больше не был объектом, а скорее свойство text и optionsValue: "text":

<select id="make" data-bind="select2:{} , options: carMakers, value:    selectedMake,   
optionsValue:'text', 
optionsText : 'text', optionsCaption : 'Select your make'"></select><br/>

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

viewModel.carTypes = ko.computed(function(){
if(viewModel.selectedMake()){
    var make = ko.utils.arrayFirst(viewModel.carMakers,function(item){
        console.log(item.text,viewModel.selectedMake());
            return item.text===viewModel.selectedMake();          
    });
    return make.childOptions;
} 
});

Это также означает, что вы можете просто использовать Selected Make: <span data-bind="text: selectedMake"></span> а не использовать скобки, поскольку вы не пытаетесь получить доступ к свойству наблюдаемого.

Вот снова скрипка: http://jsfiddle.net/jiggle/Lw2qJ/

Надеюсь, поможет.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню