2016-03-01 123 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事件,但也沒有觸發。我知道某些東西是假定綁定在虛擬機中的,但是由於這種映射器已經完成了這種工作,我不確定下拉更改時會發生什麼變化? 任何幫助將非常感激。 非常感謝, 大衛。 –

相關問題