A Small Form and Cascading Drop Down with KnockoutJS

by Avi Algaly

HTML

<script src="http://cloud.github.com/downloads/SteveSanderson/knockout/knockout-2.2.0.debug.js"></script>
<fieldset>
    <label for="resident-name">Resident Name</label>
    <input type="text" id="resident-name" data-bind="value: residentName, valueUpdate: 'afterkeydown'" />
    <label for="street-name">Street</label>
    <input type="text" id="street-name" data-bind="value: streetName, valueUpdate: 'afterkeydown'" />
    <label for="number-name">Number</label>
    <input type="text" id="number-name"  data-bind="value: numberName, valueUpdate: 'afterkeydown'" />
    <label for="country-name">CountryName</label>
    <select id="country-name" data-bind="options: availableCountries, optionsText: 'name', optionsCaption: 'Choose Country...', value: countryName"></select>
    <label for="city-name">City Name</label>
    <select id="city-name" data-bind="options: availableCities, optionsText: 'name', optionsCaption: 'Choose City...', value: cityName"></select>
    <button id="submit-command" data-bind="click: submitClick, enable: validateModel">Submit</button>
</fieldset>
<button id="show-info-command" >Show Info</button>

SCSS

fieldset {
    border: 1px dotted #bbb;
    padding: 5px;
    label {
        display: block;
        float: left;
        width: 100px;
        line-height: 22px;
        clear: left;    
    }
    input, select {
        margin-bottom: 5px;
        width: 130px;  
display:block;    
    }
}

JavaScript

var newPropertyViewModel = {
    residentName: ko.observable("John Doe"),
    streetName: ko.observable("Sesame"),
    numberName: ko.observable("5"),
    cityName: ko.observable(""),
    countryName: ko.observable(""),
    availableCountries: ko.observableArray([]),
    submitClick: function() {
        alert("Submitting data...");
    }
};

newPropertyViewModel.availableCities = ko.dependentObservable(function() {
    var country = this.countryName();
    var availableCities = {
        cities: []
    };
    if (country) {
        availableCities = ko.utils.arrayFilter(cities, function(currentCity) {
            return currentCity.countryId === country.id;
        });
    }
    if (availableCities.length && availableCities.length > 0) {
        availableCities = availableCities[0];
    }
    return availableCities.cities;
}, newPropertyViewModel);

newPropertyViewModel.validateModel = ko.computed(function() {
    var isValid = (this.residentName() || false) && (this.streetName() || false) && (this.numberName() || false) && (this.cityName() || false) && (this.countryName() || false);

    return isValid;
}, newPropertyViewModel);

ko.applyBindings(newPropertyViewModel);

$("#show-info-command").on("click", function() {
    var currentState = {
        residentName: newPropertyViewModel.residentName(),
        streetName: newPropertyViewModel.streetName(),
        numberName: newPropertyViewModel.numberName(),
        cityName: newPropertyViewModel.cityName(),
        countryName: newPropertyViewModel.countryName()
    };
    alert(JSON.stringify(currentState));
});

// load countries
var countries = [
    {
    id: 1,
    name: "Israel"},
{
    id: 2,
    name: "USA"},
{
    id: 3,
    name: "Canada"}
];

// load cities
var cities = [
    {
    countryId: 1,
    cities: [
        {
        id: 11,
        name: "Tel Aviv"},
    {
        id: 12,
        name: "Jerusalem"},
    {
        id: 13,
        name: "Haifa"},
    {
        id: 14,
        name:...