淘汰赛中的自定义下拉列表

时间:2014-04-22 22:37:24

标签: javascript jquery knockout.js knockout-2.0 knockout-mvc

我正在尝试创建一种自定义下拉列表,它将具有一个方法名称,从中获取其所有元素,在敲除模型绑定之前,它应该等待从给定的方法填充列表然后开始默认行为。

到目前为止,我成功地从给定方法填充数据。但问题是如何告诉knockout绑定等到我的init方法完成其异步工作。

ko.bindingHandlers.serviceMethod = {
        init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        var serviceName, optionsValue, optionsText, value, optionsCaption, isCompleted;

        if (element.nodeName == 'SELECT') {                
            optionsValue = allBindings().optionsValue || 'value';
            optionsText = allBindings().optionsText || 'text';                
            serviceName = valueAccessor();               

            var l = $(element);
            serviceName.apply().done(function (results) {
                l.empty();
                $.each(results.List, function (j, result) {
                    l.append($("<option />").val(result[optionsValue] || '').text(result[optionsText] || ''));
                })                    
            });
        }
    },
    update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {

        //what to do now in order to let knockout wait for list to be populated
    }
 }

我的绑定是

<select name="state" data-bind="serviceMethod:registrationService.getAllStates,value: model.state" id="ddlState"></select>

2 个答案:

答案 0 :(得分:1)

您可以在数据可用之前禁用输入元素,Extender可以执行此操作。

标记:

<select data-bind="serviceMethod:getOptions, options: options, enable:options.enable></select>

viewmodel:

function viewModel(){
    this.options=ko.observableArray().extend( { enabled:false});       
}

绑定处理程序:

ko.bindingHandlers.serviceMethod = {
     init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        var getOptionsFunction=valueAccessor();
        // deferred implemented as a callback
        getOptionsFunction(function(r){
           allBindings().options(r);               
           // call extender observable to enable the input
           allBindings().options.enabled(true); 
        } );
    },
    update:function (element, valueAccessor, allBindings, viewModel, bindingContext) {
    }    

扩展器:

ko.extenders.enabled = function(target, option) {
    target.enabled=ko.observable(option);
    return target;
};

fiddle

注意:我会将逻辑移到视图模型中,在我们的项目中,我们犯了错误,在应该转到viewModels的绑定处理程序中添加了太多编码。

答案 1 :(得分:1)

这就是我实现它的方式,首先我将淘汰赛扩展为

ko.extenders.asyncList = function (target, option) {

    var _callbackF = [];
    var result = ko.computed({
        read: function () {

            if (!target.populated()) {
                option.apply().done(_addintoList);
            } 
            return target;
        },
        deferEvaluation: true
    });

    target.populated = ko.observable(false);
    target.refresh = function () {
        target.populated(false);
    }    
    var _addintoList = function (aData) {

        ko.utils.arrayForEach(aData.List, function (item) {
            target.push(item);
        });

        if (_callbackF != undefined) {
            $.each(_callbackF, function (_f) {
                _f.apply();
            });
            _callback = undefined;
        }
        target.populated(true);
    }
    return result();
}

然后使用此扩展程序查看模型,如

staticData: function () {
    var self = this;
    var def = $.Deferred();
    self.allStates = ko.observableArray().extend({ asyncList: registrationService.getAllStates });
    self.hearUsAll = ko.observableArray().extend({ asyncList: registrationService.getAllSources });;
    self.populated = ko.computed({
        read: function () {
            if (this.allStates.populated() && this.hearUsAll.populated()) {
                return def.resolve(true);
            }
            return def;
        },
        deferEvaluation: true
    }, this);

然后我的主要功能就像

一样使用它
this.staticData.populated().done(
        function (d) {
            ko.applyBindings({ model: self.dataModel, staticData: self.staticData, view: self.viewModel })
        });