knockout.jscomputed-observable

How to set Conditional Select Menu on Load - KnockoutJS


I've been working on a two-level, conditional select menu that will change the second level options based on the first level selection.

The conditional portion is working fine, but I'm realizing I'll need to support an option on load so both select menus are already populated.

I tried setting the values of the selectedLevelOne and selectedLevelTwo observables but that didn't seem to work.

What am I doing wrong?

Here's a fiddle to illustrate: http://jsfiddle.net/mujaji/brwgetv1/1/

HTML

<div id="override-more">
<div class="form-group">
    <label class="control-label" for="leveOneSelect">Superhero/Villian</label>
    <select class="form-control" id="leveOneSelect" data-bind="options: levelOne, optionsCaption:'--Level 1--', optionsText: 'text', optionsValue: 'value', value: selectedLevelOne"></select>
</div>
<div class="form-group">
    <label class="control-label" for="levelTwoSelect">Superhero/Villian Name</label>
    <select class="form-control" id="levelTwoSelect" data-bind="options: levelTwo, optionsCaption:'--Level 2--', optionsText: 'text', optionsValue: 'value', value: selectedLevelTwo, enable: levelTwo().length">

    </select>
</div>

Javascript

function ViewModel(items) {
this.levelOne = ko.observableArray(items);
this.selectedLevelOne = ko.observable("Marvel Villian");
this.selectedLevelTwo = ko.observable("Galactus");

function getById(items, value) {
    if(!value) {
        return [];
    }

    var result = ko.utils.arrayFirst(items, function(item) {
        return item.value === value;
    });

    return result && result.childItems || [];
}

this.levelTwo = ko.computed(function(){
    var items = this.levelOne();
    var id = this.selectedLevelOne()
    return getById(items, id);
}, this);

}

var items = [
{text: "Marvel Superhero", value: "1", childItems: [
    {text: 'Captain America', value: '01'},
    {text: 'Ironman', value: '02'},
    {text: 'Wolverine', value: '03'},
    {text: 'Nightcrawler', value: '04'},
    {text: 'Spiderman', value: '05'},
    {text: 'Hulk', value: '06'},
    {text: 'Thor', value: '07'},
    {text: 'Hawkeye', value: '08'},
    {text: 'Silver Surfer', value: '09'},
    {text: 'The Thing', value: '10'},
    {text: 'Mr Fantastic', value: '11'}
]},
{text: "Marvel Villian", value: "2", childItems: [
    {text: 'Dr. Doom', value: '01'},
    {text: 'Magneto', value: '02'},
    {text: 'Juggernaut', value: '03'},
    {text: 'The Blob', value: '04'},
    {text: 'Galactus', value: '05'}
]},
{text: "DC Superhero", value: "3", childItems: [
    {text: 'Superman', value: '01'},
    {text: 'Batman', value: '02'},
    {text: 'Robin', value: '03'},
    {text: 'Wonder Woman', value: '04'},
    {text: 'Raven', value: '05'},
    {text: 'Aquaman', value: '06'}
]},
{text: "DC Villian", value: "4", childItems: [
    {text: 'Lex Luthor', value: '01'},
    {text: 'Joker', value: '02'},
    {text: 'Grundy', value: '03'},
    {text: 'The Riddler', value: '04'},
    {text: 'Lobo', value: '05'}
]}
];

var module = {};

module.sampleViewModel = new ViewModel(items);

ko.applyBindings(module.sampleViewModel, document.getElementById("override-more"));

Solution

  • you are initializing with "text" value instead of the "value" property of the bound array, the below change should fix it

    this.selectedLevelOne = ko.observable("2");
    this.selectedLevelTwo = ko.observable("05");
    

    http://jsfiddle.net/brwgetv1/2/