淘汰赛 - 是否可以将标准选择绑定与自定义绑定相结合?

时间:2013-10-31 11:28:44

标签: knockout.js jquery-chosen

这不起作用(调用自定义绑定但是下拉列表为空)

<select id="parentArea" class="chosen-select" data-bind="
   chosen:{},
   options: parentAreas,
   optionsCaption: 'Choose...',
   optionsText: 'Label',
   value: selectedParentArea">
</select>

但这可行(下拉列表已填写)

<select id="parentArea" class="chosen-select" data-bind="
   options: parentAreas,
   optionsCaption: 'Choose...',
   optionsText: 'Label',
   value: selectedParentArea">
</select>

我想在下拉列表中添加自定义绑定,但不知道如何操作。

自定义绑定很简单

ko.bindingHandlers.chosen = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
        console.log('chosen', element);
        $(element).chosen({});
    }
};

更新

.chosen({});

是来自另一段Javascript(harvesthq.github.io/chosen)的方法。

我意识到当它被注释掉时,剩余的绑定工作。 我真正需要的是运行“$(element).chosen({});”所有其他装订完成后。

更新2

在应用所有绑定后手动应用“选择”时,它运行良好。例如,我可以使用运行此JS的按钮

 function run() {
    $('.chosen-select').chosen({});
};    

我需要在所有绑定完成后自动执行(回调函数?)。 我不知道怎么做。

更新3

“parentAreas”不是静态数组。它是从Web服务加载的:

function ViewModel() {

    var self = this;

   self.init = function () {

        //load parent areas from web service
    };

    self.init(); //Running the init code
}

ko.applyBindings( new ViewModel());

我想在父区域准备就绪时初始化“选择”框自定义绑定。

更新4

新版本(有效但不可重用,因为它具有硬编码绑定)

ko.bindingHandlers.chosen = {         init:function(element,valueAccessor,allBindingsAccessor,viewModel,context){

        viewModel.parentAreas.subscribe(function(newParentAreas) {
            if (newParentAreas && newParentAreas.length > 0) {

                ko.applyBindingsToNode(element, {
                    options: viewModel.parentAreas,
                    optionsCaption: 'Choose...',
                    optionsText: 'Label',
                    value: viewModel.selectedParentArea
                });
                $(element).chosen({});
            }
        });
    }
};

//绑定只是data-bind =“selected:{}

更新5 避免多次初始化(hacky方式)

ko.bindingHandlers.parentAreaComboBox = {

    initialised: false,
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, context) {

        viewModel.parentAreas.subscribe(function (newParentAreas) {

            if (newParentAreas && newParentAreas.length > 0) {

                if (ko.bindingHandlers.parentAreaComboBox.initialised) {
                    return;
                }
                ko.applyBindingsToNode(element, {
                    options: viewModel.parentAreas,
                    optionsCaption: 'Choose...',
                    optionsText: 'Label',
                    value: viewModel.selectedParentArea
                });
                $(element).chosen({});
                ko.bindingHandlers.parentAreaComboBox.initialised = true;
            }
        });
    }
};

更新6

我写过通用解决方案(请参阅下面的答案)

4 个答案:

答案 0 :(得分:4)

它依赖于绑定顺序的反模式。

如果您有一个自定义绑定需要其他绑定才能在自身之前运行,您应该从自定义绑定中调用这些绑定,如

ko.applyBindingsToNode(element, { options: arr, value: val });

然后执行$(element).chosen

答案 1 :(得分:1)

是的,只需重新排序你的绑定(小提琴:http://jsfiddle.net/gBhbx/4/):

<select id="parentArea" class="chosen-select" data-bind="   
   options: parentAreas,
   optionsCaption: 'Choose...',
   optionsText: 'Label',
   chosen:{},
   value: selectedParentArea">
</select>

答案 2 :(得分:1)

我认为您的问题出在chosen插件本身。当您在.chosen标记上应用select时,它会更改其标记(它不再是正常的html select)。
所以在你绑定你的应用chosen自定义绑定然后更改html标记,所以你的绑定不能正常工作..

要解决这个问题,您需要首先应用自定义绑定最后 ..以便正常应用ko绑定,然后应用自定义绑定并更改您的选择(但现在您已经构建了你的选择正确)

更新

在生成option元素后运行函数,您可以使用optionsAfterRender回调。查看文档here

另一个解决方案是使用settimeout

答案 3 :(得分:1)

通用解决方案

HTML

<select id="parentArea" data-bind="comboBox:{ options: parentAreas, optionsCaption:'Choose...' , optionsText: 'Label', value: selectedParentArea }"></select>

和javascript是

   ko.bindingHandlers.comboBox = {

    init: function (element, valueAccessor, allBindingsAccessor, viewModel, context) {
        var bindings = valueAccessor();
        var optionsObservableArray = bindings.options;
        optionsObservableArray.subscribe(function (newObservableArray) {

            if (newObservableArray && newObservableArray.length > 0) {

                if (element.comboBoxInitialised) {
                    return;
                }

                ko.applyBindingsToNode(element, {
                    options: bindings.options,
                    optionsCaption: bindings.optionsCaption,
                    optionsText: bindings.optionsText,
                    value: bindings.value
                });
                $(element).chosen({});
                element.comboBoxInitialised = true;
            }
        });
    }
};