Search code examples
knockout.jsknockout-mvc

Knockout: Cascading dropdowns, second dropdown selected text


.net MVC, C#, KnockoutJS

So I have 2 dropdowns. Both whose data is being populated via Ajax call from knockout to MVC controller function. The initial setup works fine where on selection of first dropdown the second dropdown populates. What I need to do is pass the text and value selected from the second dropdown on the button click event to the next controller. I have tried both subscribe and onchange but cant get the value and text selected from the second dropdpown. Here is the code below:

Dropdown 1

  <select data-bind="options: countries ,
                   optionsText: 'Name',
                   optionsValue: 'ID',
                   value: selectedCountry,
                   optionsCaption: '--Please Select--'" asp-placeholder-for="Country" asp-for="Country"   class="form-control common-input-text"></select>

Dropdown 2

 <select data-bind="options: states ,
                optionsText: 'Name', 
                visible: ifSelected,                    
                optionsValue: 'ID',
                event: { change: selectionChanged },
                value: selectedState"
                     asp-placeholder-for="State" asp-for="State"  
                     class="form-control common-input-text"></select>

Knockout

(function () {
var viewModel = function (vmData) {

    var self = this;

    self.countries = ko.observableArray();
    self.selectedCountry = ko.observable();
    self.states = ko.observableArray();
    self.ifSelected = ko.observable(false);
    self.selectedState = ko.observable();    

    //Populate Country DDL
    $.ajax({
        url: rootDir + "/Home/GetCountry",
        type: "GET",
        contentType: "application/json",
        async: false,
        success: function (data) {
            self.countries(JSON.parse(data));
        }
    });

    //Populate state DDL based on country
    self.selectedCountry.subscribe(function (val) {           
        $.ajax({
            url: rootDir + "/Home/GetStates",
            type: "GET",
            data: { stateVal: val },
            contentType: "application/json",
            async: false,
            success: function (data) {
                var jsonData = JSON.parse(data); 
                self.ifSelected(true);                      
                    self.states(jsonData);                 
            }
        });            
    });

    //I have tried to subscribe to second dropdown but this function is never hit
    self.selectedState.subscribe(function (value) {


    });

    //I have tried to bind onchange event to state dropdown but the selected value is always null
       self.selectionChanged =  function(event) {
       var a = self.selectedState(); //null or udefined

    }    
};

var pageVM = new viewModel();
ko.applyBindings(pageVM, $("form")[0]);
})();

Solution

  • The code you've posted seems fine. "selectedState" holds the ID of the item that was selected. If you want the whole object instead of just the ID consider removing the "optionsValue: 'ID'" binding from the states dropdown.

    var viewModel = function(vmData) {
    
      var self = this;
    
      self.countries = ko.observableArray();
      self.selectedCountry = ko.observable();
      self.states = ko.observableArray();
      self.ifSelected = ko.observable(false);
      self.selectedState = ko.observable();
    
      //Populate Country DDL
      setTimeout(function(data) {
          self.countries([{ Name: 'us', ID: 1 }, { Name: 'ca', ID: 2 }, { Name: 'mx', ID: 3 }]);    
        }, 500);
    
      //Populate state DDL based on country
      self.selectedCountry.subscribe(function(val) {
      	console.log('country changed');
        setTimeout(function(data) {
            self.ifSelected(true);
            self.states([{ Name: 'ca', ID: 1 }, { Name: 'nv', ID: 2 }, { Name: 'tx', ID: 3 }]);    
        }, 500);
      });
    
      //I have tried to subscribe to second dropdown but this function is never hit
      self.selectedState.subscribe(function(value) {
        console.log('state changed');
      });
    
      //I have tried to bind onchange event to state dropdown but the selected value is always null
      self.selectionChanged = function(event) {
        var a = self.selectedState(); //null or udefined
    
      }
    };
    
    var pageVM = new viewModel();
    ko.applyBindings(pageVM);
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
    
    <select data-bind="options: countries ,
                       optionsText: 'Name',
                       optionsValue: 'ID',
                       value: selectedCountry,
                       optionsCaption: '--Please Select--'" asp-placeholder-for="Country" asp-for="Country" class="form-control common-input-text"></select>
    
    <select data-bind="options: states ,
                       optionsText: 'Name', 
                       visible: ifSelected, 
                       event: { change: selectionChanged },
                       value: selectedState" asp-placeholder-for="State" asp-for="State" class="form-control common-input-text"></select>
    
    <br/>
    selectedState: <span data-bind="text: ko.toJSON(selectedState)"></span>