2012-01-23 17 views
18

¿Hay algún modo en el enlace Knockoutjs donde puedo especificar optionsGroup? algo así como follwoingKnockoutjs seleccionar con el grupo de opciones

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

Por favor, responda.

+0

Supongo que podría usar el enlace attr como se documenta en http://knockoutjs.com/documentation/attr-binding.html – kfuglsang

+5

Aquí hay un hilo sobre cómo agregar opciones Soporte del grupo: https://github.com/SteveSanderson/knockout/pull/94 –

Respuesta

30

Tengo la respuesta de la misma, aquí está la respuesta si alguien quiere,

<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

¿podría mostrarnos la parte de Javascript? ¡¡Estoy muy interesado!! Gracias – jbartolome

0

probar esto.

(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

En muchos casos, no es necesario las opciones de sí mismos para ser observable, sólo el resultado de la selección. Aquí está el ejemplo que hace la selección del condado de UK.

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

que recuperará la opción seleccionada en viewModel.countyList.

1

Esto también permitirá un marcador de posición:

<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 serían en este formato:

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

valor Esta opción, que podría ser de valor en este sencillo ejemplo.

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

Pero para los objetos más complejos $ data sería la mejor opción.

Cuestiones relacionadas