2016-03-01 102 views
1

我一直在考虑一些KO代码维护:Knockout:如何在第一个选择值后过滤第二个下拉菜单?

<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> 

但这不适合我。顶层的东西在于它们是从数据库填充的两个下拉列表,但它们并没有连在一起。我需要第二个能够根据第一个选择的内容进行自我筛选。

我可以捕捉什么事件来捕捉顶部下拉菜单的变化?

这在一般的MVC中都很容易,但是用KO我不知道该怎么做,真的很让人沮丧!

因此,在我被迫完全抛弃KO并在正常MVC中重写它之前,任何帮助都将真正感激。

UPDATE:

,我发现这个文件(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(); 
    }); 
}); 

这似乎是什么,我需要做的,但不能figgure了我如何得到这个过滤我salesstatus取决于从WorkFlowStatus下拉列表中选择的值。目前SalesStstus下拉菜单显示所有的值,我需要根据WorkFlowStatus下拉列表中选择的内容进行筛选。

基本上,当第一个下拉列表(工作流状态发生变化时,我需要第二个下拉列表(销售状态)来过滤其结果,例如当工作流状态为预留时,销售状态将显示佣金,预留,礼物,慈善。工作流状态是在发售,销售状态将显示寄售,在提供与贷款作为选择。再加上有更多...

希望是有道理的?

真的很感激帮助的感谢!:)

+0

+1

请花几分钟分钟以熟悉在本网站上格式化的方式。问题编辑器旁边有一个帮助部分,你不能错过它。 – Tomalak

+1

另外,这里使用的'combobox'绑定是什么?这一个(https://github.com/AndersMalmgren/Knockout.Combobox)? – Tomalak

回答

2

您不会挂钩事件以观察Knockout中改变的值。小部件必然会被观察到,因此值的更改会显示在您的视图模型中。你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); 
}); 
+0

感谢您的回答,是的,这就是我所害怕的!:(因为目前时间紧迫。是否有一种快速简便的方法,可以在第一个下拉列表(workflowstatus)更新时得到通知?已经计算出如何进入销售状态数组(convertedObject.salesStatuses),我可以在传递给salesStatusModel之前操作它。但是,我需要订阅工作流状态的已更改事件,但无法弄清 –

+0

我已尝试过: ,事件:{变化:$ parent.selectionChanged} 而且还尝试: ,事件:{变化:$ .selectionChanged} 那么它要么是

但由于这个烦人的映射我不知道我可以在哪里定义这个selectionChanged事件?目前它没有被调用。 –

+0

我甚至试图挂钩一个jQuery onChange事件,但也没有触发。我知道某些东西是假定绑定在虚拟机中的,但是由于这种映射器已经完成了这种工作,我不确定下拉更改时会发生什么变化? 任何帮助将非常感激。 非常感谢, 大卫。 –

相关问题