2

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

<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="chosen:{}

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

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

4 回答 4

5

它是一种反模式,您依赖于绑定的顺序。

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

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

然后做$(element).chosen

于 2013-10-31T13:16:02.383 回答
1

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

<select id="parentArea" class="chosen-select" data-bind="   
   options: parentAreas,
   optionsCaption: 'Choose...',
   optionsText: 'Label',
   chosen:{},
   value: selectedParentArea">
</select>
于 2013-10-31T11:48:55.110 回答
1

我认为您的问题出在chosen插件本身。当您应用.chosen标签select时,它会更改其标记(不再是普通的 html select)。
因此,在您的绑定中,您首先应用chosen自定义绑定,然后更改 html 标记,因此您的绑定无法正常工作..

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

更新

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

另一个肮脏的解决方案是使用settimeout

于 2013-10-31T11:50:29.670 回答
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;
            }
        });
    }
};
于 2013-10-31T17:54:58.583 回答