淘汰赛:如何在第一个选择值后过滤第二个下拉列表?

时间:2016-03-01 11:30:39

标签: knockout.js

我得到了一些KO代码来维护:

<div class="formField" id="formFieldWorkflowStatus">
    <div id="comboWorkflowStatus" data-bind="combobox: workflowStatusModel"></div>
</div>
<div class="formField" id="formFieldSalesStatus">
    <div id="comboSalesStatus" data-bind="combobox: salesStatusModel"></div>
</div>

它似乎在它后面使用这个映射JS文件:

(function (app, ko) {
    app.namespace("mappers");

    function test()
    {
        convertedObject.salesStatuses
    }

    var 
        config = {
            "consignments": {
                create: mapInlineNotes
            },

            "charities": {
                create: mapInlineNotes
            },

            "gifts": {
                create: mapInlineNotes
            },

            ignore: ["saleStatus", "saleStatuses"]
        },


        map = function (json) {
            var convertedObject = ko.utils.parseJson(json);
            var model = ko.mapping.fromJS(convertedObject, config);

            model.salesStatusModel = new ListModel({
                isRemoteSource: false,
                currentValue: convertedObject.selectedSalesStatus,
                data: convertedObject.salesStatuses,
                onlyPreparedValues: true,
                allowNull: false,
                readonly: true
            });

            model.workflowStatusModel = new ListModel({
                isRemoteSource: false,
                currentValue: convertedObject.selectedWorkflowStatus,
                data: convertedObject.workflowStatuses,
                onlyPreparedValues: true,
                allowNull: false,
                readonly: true
            });

            return model;
        },

        toJS = function (model) {
            return ko.mapping.toJS(model);
        },

        unmapConsignment = function (consignment) {
            return ko.mapping.toJS(consignment);
        },

        mapConsignment = function (data, consignment) {
            if (!consignment) {
                return mapInlineNotes({ data: data });
            }

            return ko.mapping.fromJS(data, consignment);
        };

    function mapInlineNotes(options) {
        return app.mappers.inlineNoteContainer.map(options.data);
    }

    app.mappers.consignment = {
        map: map,
        toJS: toJS,
        unmapConsignment: unmapConsignment,
        mapConsignment: mapConsignment
    };
})(app, ko);

我发现的所有例子都不是这样的,并使用如下内容:

<select data-bind="options: workflowStatuses, value: selectedWorkflowStatus, optionsText: 'name', optionsCaption: 'Choose a make'"></select>

但这对我不起作用。顶部的东西是这样的,它们是从DB填充的两个下拉列表,但它们无论如何都没有链接在一起。我需要第二个能够根据第一个选择的内容进行过滤。

我可以捕捉哪些事件来捕捉顶部下拉列表更改?

在正常的MVC中这一切都很容易,但是对于KO我不知道该怎么做而且真的很令人沮丧!

所以在我被迫完全抛弃KO并在普通的MVC中重写它之前,任何帮助都会非常受欢迎。

更新:

我找到了这个文件(knockout.combobox.js):

/// <reference path="jquery-1.7.js" />
/// <reference path="knockout-2.2.1.debug.js" />
/// <reference path="jquery-ui-1.8.16.js" />
// Alex B

(function ($, ko) {
    var defaultKeyDownTemplateName = "defaultTemplate";
    var defaultChangeComboboxTemplateName = "specialTemplate";
    var defaultKeyDownTemplate = "<input type=\"text\" class='ignoreReadonly' data-bind=\"readonly: $data.readonly, enable: $data.editable, autocomplete: $data, value: $data.selected.value, valueUpdate: 'afterkeydown'\"/><button style='opacity: 1' tabindex=\"-1\" title=\"Show All Items\" type=\"button\" data-bind=\"enable: $data.editable, visible: !($data.nobutton), click: $data.showAll, jqueryui: {widget:'button', options:{icons:{primary:'ui-icon-triangle-1-s'}, text: false}}\">&nbsp;</button>";
    var defaultFocusChangeTemplate = "<input type=\"text\" class='ignoreReadonly' data-bind=\"readonly: $data.readonly, enable: $data.editable, autocomplete: $data, value: $data.selected.value\"/><button style='opacity: 1' tabindex=\"-1\" title=\"Show All Items\" type=\"button\" data-bind=\"enable: $data.editable, visible: !($data.nobutton), click: $data.showAll, jqueryui: {widget:'button', options:{icons:{primary:'ui-icon-triangle-1-s'}, text: false}}\">&nbsp;</button>";

    var textareaTemplateName = "textAreaTemplate";
    var textareaTemplate = "<textarea class=\"elastic\" type=\"text\" data-bind=\"readonly: $data.readonly, enable: $data.editable, autocomplete: $data, value: $data.selected.value, valueUpdate: 'afterkeydown'\"/>";

    var templateEngine = new ko.nativeTemplateEngine();

    ko.bindingHandlers.combobox = {
        init: function (element, valueAccessor) {
            templateEngine.addTemplate(defaultKeyDownTemplateName, defaultKeyDownTemplate, element);
            templateEngine.addTemplate(textareaTemplateName, textareaTemplate, element);
            templateEngine.addTemplate(defaultChangeComboboxTemplateName, defaultFocusChangeTemplate, element);
            $("textarea.elastic").elastic();
            return { 'controlsDescendantBindings': true };
        },
        update: function (element, valueAccessor, allBindingsAccessor) {
            var model = ko.utils.unwrapObservable(valueAccessor());
            if (allBindingsAccessor().enable) {
                var enabled = ko.utils.unwrapObservable(allBindingsAccessor().enable);
                model.editable = enabled;
            }
            if (model.templateName) {
                ko.renderTemplate(model.templateName, model, { templateEngine: templateEngine }, element, "replaceNode");
            } else {
                ko.renderTemplate(defaultKeyDownTemplateName, model, { templateEngine: templateEngine }, element, "replaceNode");
            }
        }
    };
})(jQuery, ko);


And also found:

ko.bindingHandlers.comboboxSelectedValue = {
        init: function (element, valueAccessor) {
            $(element).bind("change", function () {
                var accessor = valueAccessor();
                if (ko.isObservable(accessor)) {
                    accessor(element.selectedIndex != -1 ? $(element).val() : null);
                } else {
                    valueAccessor(element.selectedIndex != -1 ? $(element).val() : null);
                }
            });
        },
        update: function (element, valueAccessor) {
            if (!$(element).data("combobox")) {
                $(element).combobox(); //it is here (not in init method) to provide sorting, because there are no select options rendered by ko by the time init method is called
            }
            var value = ko.utils.unwrapObservable(valueAccessor());
            if (value != null) {
                $(element).combobox("setSelectedValue", value);
            } else {
                $(element).combobox("clearSelected");
            }
        }
    };

in a knockout.extentions.js file.

Hopefully that helps?

Someone on another forum posted this:

//Creates an observable array which changes its contents automatically, based on another value
var filteredWorkflowStatuses=ko.computed(function(){
   //Some kind of filtering, e.g
   return ko.utils.arrayFilter(convertedObject.workflowStatuses(), function(item){
      return convertedObject.selectedSalesStatus() && convertedObject.selectedSalesStatus().someProperty()==item.someProperty();
   });
});

这似乎是我需要做的事情但是无法弄清楚我如何根据从WorkFlowStatus下拉列表中选择的值来过滤我的salesstatus下拉列表。目前SalesStstus下拉列表显示所有值,我需要根据WorkFlowStatus下拉列表中选择的内容对其进行过滤。

基本上,当第一个下拉列表(工作流程状态被更改时,我需要第二个下拉列表(销售状态)来过滤其结果。例如,当工作流程状态为保留时,销售状态将显示委托,保留,礼品,慈善机构。状态为On Offer,销售状态将显示On Consignment,On offer和On Loan作为选项。另外还有更多......

希望有道理吗?

非常感谢帮助谢谢! :)

1 个答案:

答案 0 :(得分:2)

您不会挂钩事件来观察Knockout中更改的值。窗口小部件绑定到可观察对象,因此值的更改将显示在viewmodel中。您subscribe让那些可观察的人在他们改变时采取行动,或者你写了隐含订阅的computed observables

如果你是Knockout的新手并且这段代码刚被扔到你的腿上,请花一点时间来完成Knockout tutorial。这会让你更好地感受到Knockout接近事物的方式。你需要很好地理解Knockout,至少在自定义绑定处理程序方面。看起来你得到的东西需要一些重写来获得你想要的功能。

因为它是一个自定义小部件,所以它可能不会触发任何标准事件。我可以给你的最好的建议(没有完成所有的代码,也没有时间来完成所有这些代码)是在workflowStatusModel的定义之后添加这些代码:

model.workflowStatusModel.subscribe(function (newValue) {
    console.debug("Hey, it changed!", newValue);
});

如果您从中获取控制台输出,那么您可以在其中处理对其的更改。否则,查看ListModel的定义,了解可能存在您正在寻找的值的可观察成员,并尝试类似

的内容
model.workflowStatusModel.someMember.subscribe(function (newValue) {
    console.debug("Hey, it changed!", newValue);
});