【问题标题】:custom drop down list in knockout淘汰赛中的自定义下拉列表
【发布时间】:2014-06-07 12:47:42
【问题描述】:

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

到目前为止,我成功地从给定方法填充数据。但问题是如何告诉淘汰绑定等到我的 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>

【问题讨论】:

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


    【解决方案1】:

    您可以在数据可用之前禁用输入元素,Extender 可以做到这一点。

    标记:

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

    视图模型:

    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 的绑定处理程序中。

    【讨论】:

    • 感谢您的回复,您的解决方案很好,但它类似于启用下拉列表,但我需要选择从服务器提供的选项。我正在使用映射插件。请看一下这两个小提琴,第一个是我需要做的,而是选择延迟响应中的值,这个值是从服务器以 JSON 格式给出的,用于从映射插件获取视图模型。 jsfiddle.net/u578D/1jsfiddle.net/R26pr/1
    • 使用第二个扩展器对可观察对象进行延迟初始化。见jsfiddle.net/R26pr/2
    • 这是处理这种情况的好方法,我通过使用名为“填充”的可观察对象扩展基于 ajax 的变量来实现它,并在我收到来自服务器和我的 viewModel 的 ajax 响应时在 onDemandObservable 中实现它我为所有基于 ajax 的 observables 使用了一个计算 observable 来填充并返回一个延迟对象,并承诺我在我的模块引导文件中应用绑定。
    【解决方案2】:

    这就是我实现它的方式,首先我像延长淘汰赛一样

    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 })
            });  
    

    【讨论】:

    • 如果专家可以帮助我找到比这更好的解决方案,我将分享这个
    猜你喜欢
    • 2014-03-19
    • 2015-08-15
    • 2016-05-27
    • 2013-02-14
    • 2014-10-07
    • 2015-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多