2012-01-23 30 views
18

Có cách nào trong Knockoutjs ràng buộc nơi tôi có thể chỉ định optionsGroup không? một cái gì đó như follwoingKnockoutjs chọn với nhóm tùy chọn

<select data-bind="options: collection, optionsText: 'Text', optionsGroup: 'Group'/> 

Vui lòng trả lời.

+0

Tôi đoán bạn có thể sử dụng liên kết attr như được ghi trong http://knockoutjs.com/documentation/attr-binding.html – kfuglsang

+5

Đây là một chủ đề về cách thêm tùy chọnNhóm hỗ trợ: https://github.com/SteveSanderson/knockout/pull/94 –

Trả lời

30

tôi có câu trả lời giống nhau, đây là câu trả lời nếu ai muốn,

<td><select class="fieldValue" data-bind="foreach: $root.AvailableFields, value: FieldId, event :{ change: $root.onFieldSelectionChange}"> 
     <optgroup data-bind="attr: {label: FieldGroupName}, foreach: Fields"> 
      <option data-bind="text: HeaderText, value: FieldId"></option> 
     </optgroup> 
    </select> 
    </td> 
+0

bạn có thể vui lòng cho chúng tôi xem phần javascript được không ?? Tôi thực sự quan tâm !! Cảm ơn – jbartolome

0

Hãy thử điều này.

(function() { 
ko.bindingHandlers["groupedOptions"] = { 
    update: function (element, valueAccessor, allBindingsAccessor) { 
     if (element.tagName != "SELECT") 
      throw new Error("groupedOptions binding applies only to SELECT elements"); 

     var previousSelectedValues = []; 
     for (var i = 0; i < element.childNodes.length; i++) { 
      var node = element.childNodes[i]; 
      if (node.tagName == "OPTGROUP") { 
       if (node.childNodes != undefined) { 
        for (var k = 0; k < node.childNodes.length; k++) { 
         var childNode = node.childNodes[k]; 
         if (childNode.tagName && childNode.tagName && childNode.tagName == "OPTION" && childNode.selected) { 
          previousSelectedValues.push(ko.selectExtensions.readValue(childNode)); 
         } 
        } 
       } 
      } else if (node.tagName && node.tagName == "OPTION" && node.selected) { 
       previousSelectedValues.push(ko.selectExtensions.readValue(node)); 
      } 
     } 

     var previousScrollTop = element.scrollTop; 

     var value = ko.utils.unwrapObservable(valueAccessor()); 

     // Clear existing elements 
     element.innerHTML = ""; 

     if (value) { 
      var allBindings = allBindingsAccessor(); 
      if (typeof value.length != "number") 
       value = [value]; 
      if (allBindings['optionsCaption']) { 
       var option = document.createElement("OPTION"); 
       option.innerHTML = allBindings['optionsCaption']; 
       ko.selectExtensions.writeValue(option, undefined); 
       element.appendChild(option); 
      } 

      var optionsGroupNamesValue = allBindings['optionsGroupNames']; 

      // Group values into optgroups 
      var groupedOptions = []; 
      var optionsGroupValue = allBindings['optionsGroup']; // undefined if not given 
      for (var i = 0, j = value.length; i < j; i++) { 
       var optionsGroup = null; 
       if (typeof optionsGroupValue == "function") 
        optionsGroup = optionsGroupValue(value[i]); 
       else if (typeof optionsGroupValue == "string") 
        optionsGroup = value[i][optionsGroupValue]; 
       else 
        optionsGroup = ""; 
       if (typeof groupedOptions[optionsGroup] == "undefined") 
        groupedOptions[optionsGroup] = []; 

       groupedOptions[optionsGroup].push(value[i]); 
      } 

      // Create HTML elements 
      for (var groupName in groupedOptions) { 
       var optgroup = null; 
       // Add an OPTGROUP for all groups except for "" 
       if (groupName != "") { 
        optgroup = document.createElement("OPTGROUP"); 
        optgroup.label = groupName; 
        element.appendChild(optgroup); 
       } 

       // Create HTML elements for options within this group 
       for (var i = 0, j = groupedOptions[groupName].length; i < j; i++) { 
        var valueGroup = groupedOptions[groupName]; 
        var option = document.createElement("OPTION"); 
        var optionValue = typeof allBindings['optionsValue'] == "string" ? valueGroup[i][allBindings['optionsValue']] : valueGroup[groupName][i]; 

        // Pick some text to appear in the drop-down list for this data value 
        var optionsTextValue = allBindings['optionsText']; 
        if (typeof optionsTextValue == "function") 
         optionText = optionsTextValue(valueGroup[i]); // Given a function; run it against the data value 
        else if (typeof optionsTextValue == "string") 
         optionText = valueGroup[i][optionsTextValue]; // Given a string; treat it as a property name on the data value 
        else 
         optionText = optionValue; // Given no optionsText arg; use the data value itself 

        optionValue = ko.utils.unwrapObservable(optionValue); 
        optionText = ko.utils.unwrapObservable(optionText); 
        ko.selectExtensions.writeValue(option, optionValue); 

        option.innerHTML = optionText.toString(); 

        if (optgroup != null) 
         optgroup.appendChild(option); 
        else 
         element.appendChild(option); 
       } 
      } 

      // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document. 
      // That's why we first added them without selection. Now it's time to set the selection. 
      var newOptions = element.getElementsByTagName("OPTION"); 
      var countSelectionsRetained = 0; 

      for (var i = 0, j = newOptions.length; i < j; i++) { 
       if (ko.utils.arrayIndexOf(previousSelectedValues, ko.selectExtensions.readValue(newOptions[i])) >= 0) { 
        ko.utils.setOptionNodeSelectionState(newOptions[i], true); 
        countSelectionsRetained++; 
       } 
      } 

      if (previousScrollTop) 
       element.scrollTop = previousScrollTop; 
     } 
    } 
}; 

ko.bindingHandlers['selectedOptions'] = { 
    getSelectedValuesFromSelectNode: function (selectNode) { 
     var result = []; 
     var nodes = selectNode.childNodes; 
     for (var i = 0, j = nodes.length; i < j; i++) { 
      var node = nodes[i]; 
      if ((node.tagName == "OPTGROUP") && node.childNodes != null) { 
       var subResult = this.getSelectedValuesFromSelectNode(node); 
       for (var k = 0; k < subResult.length; k++) { 
        result.push(subResult[k]); 
       } 
      } 
      else { 
       if ((node.tagName == "OPTION") && node.selected) 
        result.push(ko.selectExtensions.readValue(node)); 
      } 
     } 

     return result; 
    }, 
    setSelectedValuesFromSelectNode: function (selectNode, newValue) { 
     var nodes = selectNode.childNodes; 
     for (var i = 0; i < nodes.length; i++) { 
      var node = nodes[i]; 
      if (node.tagName == "OPTION") { 
       ko.utils.setOptionNodeSelectionState(node, ko.utils.arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0); 
      } 
      else if (node.tagName == "OPTGROUP") { 
       for (var k = 0; k < node.childNodes.length; k++) { 
        var childNode = node.childNodes[k]; 
        if (childNode.tagName && childNode.tagName == "OPTION") { 
         ko.utils.setOptionNodeSelectionState(childNode, ko.utils.arrayIndexOf(newValue, ko.selectExtensions.readValue(childNode)) >= 0); 
        } 
       } 
      } 
     } 
    }, 
    'init': function (element, valueAccessor, allBindingsAccessor) { 
     ko.utils.registerEventHandler(element, "change", function() { 
      var value = valueAccessor(); 
      if (ko.isWriteableObservable(value)) 
       value(ko.bindingHandlers['selectedOptions'].getSelectedValuesFromSelectNode(this)); 
      else { 
       var allBindings = allBindingsAccessor(); 
       if (allBindings['_ko_property_writers'] && allBindings['_ko_property_writers']['value']) 
        allBindings['_ko_property_writers']['value'](ko.bindingHandlers['selectedOptions'].getSelectedValuesFromSelectNode(this)); 
      } 
     }); 
    }, 
    'update': function (element, valueAccessor) { 
     if (element.tagName != "SELECT") 
      throw new Error("values binding applies only to SELECT elements"); 

     var newValue = ko.utils.unwrapObservable(valueAccessor()); 
     if (newValue && typeof newValue.length == "number") { 
      ko.bindingHandlers['selectedOptions'].setSelectedValuesFromSelectNode(element, newValue); 
     } 
    } 
}; 
})(); 



<select data-bind="groupedOptions: collection, optionsText: 'Text', optionsValue: 'Value', optionsGroup: 'Group', selectedOptions: Selected"></select> 

jsfiddle

source

2

Trong nhiều trường hợp, bạn không cần các tùy chọn tự nhận là quan sát được, chỉ là kết quả của sự lựa chọn. Đây là ví dụ về lựa chọn quận của Anh.

HTML:

<div class="form-group"> 
    <label for="county">County</label> 
     <select class="fieldValue" data-bind="foreach: $root.countyList, value: orgCounty"> 
      <optgroup data-bind="attr: {label: label}, foreach: counties"> 
      <option data-bind="text: label, value: label"></option> 
      </optgroup> 
     </select> 
</div> 

JS:

viewModel.countyList = getCountyList(); 
viewModel.orgCounty = ko.observable('London'); // Put default value here 

function getCountyList() { 
    var $arrayCounties = [ 
     { "label" : "England", "counties" : [ 
      { "label" : "Bedfordshire"}, 
      { "label" : "Berkshire"}, 
      { "label" : "Bristol"}, 
      { "label" : "Buckinghamshire"}, 
      { "label" : "Cambridgeshire"}, 
      { "label" : "Cheshire"}, 
      { "label" : "City of London"}, 
      { "label" : "Cornwall"}, 
      { "label" : "Cumbria"}, 
      { "label" : "Derbyshire"}, 
      { "label" : "Devon"}, 
      { "label" : "Dorset"}, 
      { "label" : "Durham"}, 
      { "label" : "East Riding of Yorkshire"}, 
      { "label" : "East Sussex"}, 
      { "label" : "Essex"}, 
      { "label" : "Gloucestershire"}, 
      { "label" : "Greater London"}, 
      { "label" : "Greater Manchester"}, 
      { "label" : "Hampshire"}, 
      { "label" : "Herefordshire"}, 
      { "label" : "Hertfordshire"}, 
      { "label" : "Isle of Wight"}, 
      { "label" : "Kent"}, 
      { "label" : "Lancashire"}, 
      { "label" : "Leicestershire"}, 
      { "label" : "Lincolnshire"}, 
      { "label" : "Merseyside"}, 
      { "label" : "Norfolk"}, 
      { "label" : "North Yorkshire"}, 
      { "label" : "Northamptonshire"}, 
      { "label" : "Northumberland"}, 
      { "label" : "Nottinghamshire"}, 
      { "label" : "Oxfordshire"}, 
      { "label" : "Rutland"}, 
      { "label" : "Shropshire"}, 
      { "label" : "Somerset"}, 
      { "label" : "South Yorkshire"}, 
      { "label" : "Staffordshire"}, 
      { "label" : "Suffolk"}, 
      { "label" : "Surrey"}, 
      { "label" : "Tyne and Wear"}, 
      { "label" : "Warwickshire"}, 
      { "label" : "West Midlands"}, 
      { "label" : "West Sussex"}, 
      { "label" : "West Yorkshire"}, 
      { "label" : "Wiltshire"}, 
      { "label" : "Worcestershire"} ]}, 
     { "label" : "Wales", "counties" : [ 
      { "label" : "Anglesey"}, 
      { "label" : "Brecknockshire"}, 
      { "label" : "Caernarfonshire"}, 
      { "label" : "Carmarthenshire"}, 
      { "label" : "Cardiganshire"}, 
      { "label" : "Denbighshire"}, 
      { "label" : "Flintshire"}, 
      { "label" : "Glamorgan"}, 
      { "label" : "Merioneth"}, 
      { "label" : "Monmouthshire"}, 
      { "label" : "Montgomeryshire"}, 
      { "label" : "Pembrokeshire"}, 
      { "label" : "Radnorshire"} ]}, 
     { "label" : "Scotland", "counties" : [ 
      { "label" : "Aberdeenshire"}, 
      { "label" : "Angus"}, 
      { "label" : "Argyllshire"}, 
      { "label" : "Ayrshire"}, 
      { "label" : "Banffshire"}, 
      { "label" : "Berwickshire"}, 
      { "label" : "Buteshire"}, 
      { "label" : "Cromartyshire"}, 
      { "label" : "Caithness"}, 
      { "label" : "Clackmannanshire"}, 
      { "label" : "Dumfriesshire"}, 
      { "label" : "Dunbartonshire"}, 
      { "label" : "East Lothian"}, 
      { "label" : "Fife"}, 
      { "label" : "Inverness-shire"}, 
      { "label" : "Kincardineshire"}, 
      { "label" : "Kinross"}, 
      { "label" : "Kirkcudbrightshire"}, 
      { "label" : "Lanarkshire"}, 
      { "label" : "Midlothian"}, 
      { "label" : "Morayshire"}, 
      { "label" : "Nairnshire"}, 
      { "label" : "Orkney"}, 
      { "label" : "Peeblesshire"}, 
      { "label" : "Perthshire"}, 
      { "label" : "Renfrewshire"}, 
      { "label" : "Ross-shire"}, 
      { "label" : "Roxburghshire"}, 
      { "label" : "Selkirkshire"}, 
      { "label" : "Shetland"}, 
      { "label" : "Stirlingshire"}, 
      { "label" : "Sutherland"}, 
      { "label" : "West Lothian"}, 
      { "label" : "Wigtownshire"} ]}, 
     { "label" : "Northern Ireland", "counties" : [ 
      { "label" : "Antrim"}, 
      { "label" : "Armagh"}, 
      { "label" : "Down"}, 
      { "label" : "Fermanagh"}, 
      { "label" : "Londonderry"}, 
      { "label" : "Tyrone"} ]} 
     ]; 

    return $arrayCounties; 
} 

Bạn sẽ lấy tùy chọn được chọn trong viewModel.countyList.

1

này cũng sẽ cho phép một giữ chỗ:

<select class="form-control needsclick" data-bind="value: Value"> 
    <option value="" disabled selected>Select Value...</option> 
    <!-- ko foreach: Group --> 
    <optgroup data-bind="attr: { label: Label }, foreach: Collection"> 
     <option data-bind="text: Label, value: $data"></option> 
    </optgroup> 
    <!-- /ko --> 
</select> 

JS sẽ ở định dạng này:

self.Group = ko.pauseableComputed(function() { 
    var groups = [ 
    { 
     Label: 'Group 1', 
     Collection: [ 
      { Label: 'Data 1', Value: 'Data 1' }, 
      { Label: 'Data 2', Value: 'Data 2' }, 
     ] 
    }, 
    { 
     Label: 'Group 2', 
     Collection: [ 
      { Label: 'Data 3', Value: 'Data 3' }, 
      { Label: 'Data 4', Value: 'Data 4' }, 
     ] 
    }, 
    ] 
    return groups; 
}) 

Tùy chọn này có giá trị, có thể là giá trị trong trường hợp đơn giản này.

<option data-bind="text: Label, value: Value"></option> 

Nhưng đối với đối tượng phức tạp hơn, dữ liệu $ sẽ là lựa chọn tốt hơn.

Các vấn đề liên quan