Search code examples
bindingknockout.jshtml-selectcascading

knockout js unable to bind cascading dropdown


I'm new to knockout, and trying to create work out how to populate a second dropdown list based on a selection made in the first. I've been basing my code on the first fiddle provided by rpn in this conversation.

Here is my markup

<div data-bind="visible: selectedDate">
  <span data-bind="text: selectedDate() ? selectedDate().logDate : 'unknown'"></span>
</div>
<br />

<div data-bind="visible: selectedDate">
    <select data-bind="options: filenames,
                       optionsText: name
                       value: selectedFiles"
            multiple="true"></select>
</div>

and the javascript

var modelData = {Id:1,
                 DownloadFiles: [
                  {LogDate:"01/12/2012",
                   Filenames: [
                     "File.000", "File.001"]},
                  {LogDate:"02/12/2012",
                   Filenames: [
                     "File.000", "File.001", "File.002"]},
                  {LogDate:"03/12/2012",
                   Filenames: [
                     "File.000", "File.001", "File.002", "File.003"]},
                  {LogDate:"04/12/2012",
                   Filenames: [
                     "File.000", "File.001", "File.002", "File.003"]}
                 ]};

function AvailableDate(date, filenames) {
    var self = this;
    self.logDate = ko.observable(date);
    this.filenames = ko.observableArray(ko.utils.arrayMap(filenames || [], function(filename) {
        return new Filename(filename.name);
    }));
}

function Filename(name) {
    this.name = ko.observable(name);    
}
var viewModel = {
    downloadFiles : ko.observableArray(),
    selectedDate : ko.observable(), // Nothing selected by default
    selectedFiles : ko.observableArray() // Nothing selected by default
};

ko.utils.arrayForEach(modelData.DownloadFiles, function(availableDate) {
   viewModel.downloadFiles.push(new AvailableDate(availableDate.LogDate, availableDate.filenames));
});

ko.applyBindings(viewModel);

I just cannot see the problem with the binding to the second dropdown.


Solution

  • Many thanks to nemesv for this solution.

    Here is the markup:

    <select data-bind="options: downloadFiles,
                       optionsText: 'logDate', 
                       value: selectedDate, 
                       optionsCaption: 'Select Date'"></select>
    
    <div data-bind="visible: selectedDate">
      <span data-bind="text: selectedDate() ? selectedDate().logDate : 'unknown'">
      </span>
    </div>
    <br />
    
    <div data-bind="visible: selectedDate">
      <!-- ko with: selectedDate -->
        <select data-bind="options: filenames,
                           optionsText: 'name',
                           selectedOptions: $root.selectedFiles"
                multiple="true"></select>
      <!-- /ko -->
      <span data-bind="text: ko.toJSON(selectedFiles())"></span>
    </div>
    

    and the javascript

    var modelData = {Id:1,
                 DownloadFiles: [
                  {LogDate:"01/12/2012",
                   Filenames: [
                     "File.000", "File.001"]},
                  {LogDate:"02/12/2012",
                   Filenames: [
                     "File.000", "File.001", "File.002"]},
                  {LogDate:"03/12/2012",
                   Filenames: [
                     "File.000", "File.001", "File.002", "File.003"]},
                  {LogDate:"04/12/2012",
                   Filenames: [
                     "File.000", "File.001", "File.002", "File.003"]}
                 ]};
    
    
    function AvailableDate(date, filenames) {
        var self = this;
        self.logDate = ko.observable(date);
        this.filenames = ko.observableArray(ko.utils.arrayMap(filenames || [], function(filename) {
            return new Filename(filename);
        }));
    }
    
    function Filename(name) {
        this.name = ko.observable(name);    
    }
    var viewModel = {
        downloadFiles : ko.observableArray(),
        selectedDate : ko.observable(), // Nothing selected by default
        selectedFiles : ko.observableArray() // Nothing selected by default
    };
    
    ko.utils.arrayForEach(modelData.DownloadFiles, function(availableDate) {
       viewModel.downloadFiles.push(new AvailableDate(availableDate.LogDate, availableDate.Filenames));
    });
    
    ko.applyBindings(viewModel);
    

    And thank you for the prompt delixfe. I understand why leaving the solution on jsfiddle only is a bad idea.