使用knockout.js和select2级联下拉列表

时间:2014-02-19 21:10:18

标签: jquery knockout.js jquery-select2 cascadingdropdown

请参阅此jsfiddle

我遇到两个问题:

  1. 我无法返回所选对象的(cascadingOption)文本。
  2. 我迷失了如何忠实地将下拉菜单翻译成select2。
  3. 具体来说,这个:

        <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 Object]返回到屏幕。如果我将最后一行改为span data-bind="text: selectedMake.text"则不返回任何内容。但是,如果我从淘汰赛中使用subscribe并登录到控制台,我可以返回object.text吗?

    第二个问题是我通过将select2: { }添加到其数据绑定属性来更改第一个选择标记。这将正确地将下拉列表更改为select2样式,但所有级联属性都会崩溃。

    非常感谢任何帮助或指导。

2 个答案:

答案 0 :(得分:2)

selectedMake是一个可观察的,它的值将是cascadingOption实例。要在span:text绑定中使用它,您需要:

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

当你使用subscribe时它会起作用,因为你得到了observable的值。


Select2尝试将select元素与其内部状态同步。不幸的是,它依赖于具有Id值的每个选项。因为您不使用optionsValue绑定,所以这不起作用。我也使用select2但是我已经改变了他们的代码以使用optionIndex而不是Id和一个相当复杂的select2绑定来管理差异,比如Ajax和multiselect。

但是,您的示例使用select2 ...

  1. 创建一个observable来存储Id。
  2. 更改您的值绑定以使用Id observable
  3. 添加optionsValue绑定以从源选项返回唯一ID。这将用于同步 select2 选项和选择选项。
  4. 添加订阅Id observable以过滤选项并从选项数组中返回对象
  5. 添加对observable值的订阅以保持Id同步(注意2个订阅之间的无限循环)
  6. 我已更新了您的JSFiddle,但差异如下。在这里我创建一个包装函数来构建一个observable / id对,其中2之间有订阅。 select绑定具有不同的值绑定值,以及添加的optionValue绑定 span绑定具有不同的文本绑定值。

    <强> 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');
    

答案 1 :(得分: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/

希望它有所帮助。