Search code examples
javascriptobjectselectknockout.jsknockout-mvc

How to set value in select options from complex objects using knockout?


How to create two select box from the given object? I need to create two select option box with Country dropdown and State dropdown Selection.

const optionsList =  ko.observableArray ([
    {
        'AD':{'name':'Andora'},
        'AE':{'name':"United Arab Emirates"},
        'AG':{'name':"Antigua & Barbuda"},
        'ES':{'name':"Spain", 'regions':{
                "22": {
                    "code": "A Coruсa",
                    "name": "A Coruña"
                },
                "23": {
                    "code": "Alava",
                    "name": "Alava"
                },
                "24": {
                    "code": "Albacete",
                    "name": "Albacete"
                }
                "25": {
                    "code": "Zaragoza",
                    "name": "Zaragoza"
                }
            }},
        'AT':{'name':"Austria", 'regions':{
                "95": {
                    "code": "WI",
                    "name": "Wien"
                },
                "96": {
                    "code": "NO",
                    "name": "Niederösterreich"
                }
            }},
        'AU':{'name':"Australia", 'regions':{
                "569": {
                    "code": "ACT",
                    "name": "Australian Capital Territory"
                },
                "570": {
                    "code": "NSW",
                    "name": "New South Wales"
                },
                "571": {
                    "code": "VIC",
                    "name": "Victoria"
                },
                "572": {
                    "code": "QLD",
                    "name": "Queensland"
                }
            }}
    }
])

I want to create two dropdown using knockout JS.

  1. Country List
  2. Region list if object contains the region list in object. (like Spain, Austria and Australia)

I am not sure how to create two select box in knockout using the above given object.

Thank you for any useful information.


Solution

  • You can define a regions computed that looks at a selected country and only returns its regions:

    const regions = ko.pureComputed(
      () => selectedCountry()?.regions ?? []
      //        can be null -^         ^^- if a country has no regions,
      //                                   return an empty list
    );
    

    The data you posted uses objects where I'd expect arrays, so it's slightly different. Here's a runnable example:

    const countries = Object.values(getData());
    const selectedCountry = ko.observable(null);
    
    const regions = ko.pureComputed(
      () => Object.values(
        selectedCountry()?.regions ?? {}
      )
    );
    const selectedRegion = ko.observable(null);
    
    
    ko.applyBindings({ countries, selectedCountry, regions, selectedRegion });
    
    function getData() {
      return {
        'AD': {
          'name': 'Andora'
        },
        'AE': {
          'name': "United Arab Emirates"
        },
        'AG': {
          'name': "Antigua & Barbuda"
        },
        'ES': {
          'name': "Spain",
          'regions': {
            "22": {
              "code": "A Coruсa",
              "name": "A Coruña"
            },
            "23": {
              "code": "Alava",
              "name": "Alava"
            },
            "24": {
              "code": "Albacete",
              "name": "Albacete"
            },
            "25": {
              "code": "Zaragoza",
              "name": "Zaragoza"
            }
          }
        },
        'AT': {
          'name': "Austria",
          'regions': {
            "95": {
              "code": "WI",
              "name": "Wien"
            },
            "96": {
              "code": "NO",
              "name": "Niederösterreich"
            }
          }
        },
        'AU': {
          'name': "Australia",
          'regions': {
            "569": {
              "code": "ACT",
              "name": "Australian Capital Territory"
            },
            "570": {
              "code": "NSW",
              "name": "New South Wales"
            },
            "571": {
              "code": "VIC",
              "name": "Victoria"
            },
            "572": {
              "code": "QLD",
              "name": "Queensland"
            }
          }
        }
      }
    };
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
    
    <select data-bind="
      options: countries, 
      value: selectedCountry,
      optionsText: 'name'
    "></select>
    
    <select data-bind="
      options: regions, 
      value: selectedRegion,
      optionsText: 'name',
      visible: regions().length
    "></select>
    
    <pre data-bind="text: JSON.stringify({ country: selectedCountry(), region: selectedRegion() }, null, 2)"></pre>