Dynamic country specific templating (unpreserving)

by bombo

HTML

<script src="http://rniemeyer.github.com/KnockMeOut/Scripts/jquery.tmpl.js"></script>
<script src="http://cloud.github.com/downloads/SteveSanderson/knockout/knockout-1.2.1.debug.js"></script>
<script id="formTempPermDE" type="text/html">
    <form id="form1" action="" method="POST">
        <fieldset>
            <legend>Permanent</legend>
            <label for="permStreet">Straße: </label>
            <input id="permStreet" type="text" data-bind="value: Street" /><br />
            <label for="permZIP">PLZ: </label>
            <input id="permZIP" type="text" data-bind="value: ZIP" /><br />
            <label for="permCity">Stadt: </label>
            <input id="permCity" type="text" data-bind="value: City" /><br />
            <label for="permCountry">Land: </label>
            <select id="permCountry" 
                data-bind="
                    options: viewModel.permCountries,
                    optionsText: 'Name',
                    optionsValue: 'Code',
                    value: Country
                "
            ></select>
        </fieldset>
    </form>
</script>

<script id="formTempPermUS" type="text/html">
    <form id="form1" action="" method="POST">
        <fieldset>
            <legend>Permanent</legend>
            <input id="permStreet" type="text" data-bind="value: Street" />
            <label for="permStreet">&larr; Street</label><br />
            <input id="permZIP" type="text" data-bind="value: ZIP" />
            <label for="permZIP">&larr; ZIP</label><br />
            <input id="permCity" type="text" data-bind="value: City" />
            <label for="permCity">&larr; City</label><br />
            <input id="permState" type="text" data-bind="value: State" />
            <label for="permState" class="bold">&larr; State</label><br />
            <select id="permCountry" 
                data-bind="
                    options: viewModel.permCountries,
                    optionsText: 'Name',
                    optionsValue:...

CSS

fieldset {
    border: 1px dotted #999;
    margin: 10px;
    padding: 5px;
}

.bold {
    font-weight: bold;
}

JavaScript

function Address (country, street, zip, city, state, hasGreenCard) {
    this.Street = ko.observable(street);
    this.ZIP = ko.observable(zip);
    this.City = ko.observable(city);
    this.State = ko.observable(state);
    this.Country = ko.observable(country);
    this.HasGreenCard = ko.observable(hasGreenCard);
    
    this.Country.subscribe(function(newValue) {
        var countryOption = ko.utils.arrayFirst(viewModel.permCountries() || viewModel.futCountries, function(country) {
            return country.Code === newValue;
        });
        
        if (countryOption) {
            ko.utils.arrayForEach(countryOption.ExcludeFields, function(field) {
                if (this[field] && ko.isWriteableObservable(this[field])) {
                    this[field](null);
                }
            }.bind(this));
        }
    }, this);
}

function CountryOption(name, code, excludeFields) {
    this.Name = name;
    this.Code = code;
    this.ExcludeFields = excludeFields || [];
}

var viewModel = {
    permCountries: ko.observableArray([
        new CountryOption('Deutschland', 'PermDE', ['State', 'HasGreenCard']),
        new CountryOption('USA', 'PermUS', ['HasGreenCard'])
    ]),
    futCountries: ko.observableArray([
        new CountryOption('Deutschland', 'FutDE', ['State', 'HasGreenCard']),
        new CountryOption('USA', 'FutUS', ['State'])
    ]),
    permanent: new Address('PermDE'),
    future: new Address('FutDE')
};

viewModel.tmpl1 = ko.dependentObservable(function() {
    if (this.Country()) {
        return 'formTemp' + this.Country();
    }
}, viewModel.permanent);

viewModel.tmpl2 = ko.dependentObservable(function() {
    if (this.Country()) {
        return 'formTemp' + this.Country();
    }
}, viewModel.future);

$(document).ready(function() {
    ko.applyBindings(viewModel);
});