Mapping plugin test for complex view model

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 src="https://github.com/SteveSanderson/knockout.mapping/raw/master/build/output/knockout.mapping-latest.debug.js"></script>
<div id="addressNode">
    <div class="container">
        <div data-bind="safeTemplate: { name: 'AddressEntry', data: Addresses()[0] }"></div>
        <div data-bind="safeTemplate: { name: 'AddressEntry', data: Addresses()[3] }"></div>
        <div data-bind="visible: Addresses().length != 4">
            <button data-bind="click: Add">Add one</button>
        </div>
    </div>
    
    <div class="container">
        <div data-bind="safeTemplate: { name: 'AddressEntry', data: Addresses()[1] }"></div>
        <div data-bind="safeTemplate: { name: 'AddressEntry', data: Addresses()[2] }"></div>
    </div>
</div>

<div id="debug">
    <h2>Debug: </h2>
    <div id="output" data-bind="html: formatJson(ko.toJSON(Module.AddressModel))"></div>
</div>
    
<!-- Templates -->

<script id="AddressEntry" type="text/html">
    <div class="entry">
        <div class="field">
            <label for="firstname">First name: </label>
            <input type="text" id="firstname" data-bind="value: Firstname" />
        </div>
        <div class="field">
            <label for="lastname">Last name: </label>
            <input type="text" id="lastname" data-bind="value: Lastname" />
        </div>
        <div class="field">
            <label for="street">City: </label>
            <input type="text" id="street" data-bind="value: City" />
        </div>
        <div class="field">
            <label for="addressType">Type: </label>
            <select id="addressType" 
                data-bind="
                    options: AddressTypes, 
                    value: AddressType, 
                    optionsValue: 'Element',
                    optionsText:...

CSS

.container {
    border: 1px solid #aaa;
    z-index: 10;
    -moz-box-shadow: 2px 2px 5px #888888; /* Firefox 3.6 and earlier */
    -webkit-box-shadow: 2px 2px  #888888; /* Safari and Chrome */
    box-shadow: 2px 2px 5px #888888;
    width: 45%;
    border-radius: 10px;
    -moz-border-radius: 10px; /* Firefox 3.6 and earlier */
    padding: 10px;
    float: left;
    margin-right: 10px;
}

.entry {
    margin-top: 15px;
}

.field {
    margin: 5px;
}

.field label {
    display: inline-block;
    width: 120px;
    text-align: right;
}

.toolbox {
    text-align: right;
}

button {
    background: #ccc;
    border: 1px solid #999;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: 4px;
    -moz-border-radius: 4px; /* Firefox 3.6 and earlier */
    -moz-box-shadow: 1px 1px 5px #888888; /* Firefox 3.6 and earlier */
    -webkit-box-shadow: 1px 1px 5px #888888; /* Safari and Chrome */
    box-shadow: 1px 1px 5px #888888;
}

button:hover {
    background: #ccc;
    border: none;
    padding: 5px 9px;
    -moz-box-shadow: none; /* Firefox 3.6 and earlier */
    -webkit-box-shadow: none; /* Safari and Chrome */
    box-shadow: none;
}

button:active {
    background: #ccc;
    border: none;
    padding: 5px 9px;
    -moz-box-shadow: 1px 1px 5px #888888 inset; /* Firefox 3.6 and earlier */
    -webkit-box-shadow: 1px 1px 5px #888888 inset; /* Safari and Chrome */
    box-shadow: 1px 1px 5px #888888 inset;
}

.container > .toolbox {
    border-top: 1px dotted #999;
    margin-top: 10px;
    padding-top: 10px;
}

#debug {
    clear: both;
    padding-top: 20px;
}

#debug h2 {
    border-top: 1px dotted #999;
    padding-top: 10px;
    font-family: sans-serif;
}

#output {
    margin: 2px;
    padding: 5px;
    background: #ccc;
    font-family: monospace;
    -moz-box-shadow: 2px 2px 3px #888 inset; /* Firefox 3.6 and earlier */
    -webkit-box-shadow: 2px 2px 3px #888 inset; /* Safari and Chrome */
    box-shadow: 2px 2px 3px #888 inset;
    text-shadow:...

JavaScript

function VM_AddressesHeader (ModelID, Action) {
    this.ModelID = ModelID;
    this.Action = Action;
}

function VM_AddressType(data) {
    this.Element = data.Element;
    this.Value = data.Value;
}

function VM_AddressesStructure (data) {

    this.Header = Module.AddressModel.Header;

    this.GUID = ko.observable();
    this.AddressType = ko.observable();
    this.Lastname = ko.observable();
    this.Firstname = ko.observable();
    this.City = ko.observable();
    
    ko.mapping.fromJS(data, {}, this);
    
    // ValueHelps References
    this.AddressTypes = Module.AddressModel.AddressTypes;

    // Actions
    this.Update = function () {
        ExecuteCmd('Update', this, AddressesCallback);
    };
    this.Delete = function () {
        ExecuteCmd('Delete', this, AddressesCallback);
    };
    
    // SearchHelps
    this.GetCities = function () { ExecuteCmd('GetCities', this, AddressesCallback); };
    
}

VM_AddressesStructure.prototype.toJSON = function() {
    var copy = ko.toJS(this);
    delete copy.AddressTypes;
    delete copy.__ko_mapping__;
    return copy;
};

function NewProp(data) {
    this.Number = ko.observable();
    this.Text = ko.observable();
    ko.mapping.fromJS(data, {}, this);
}

NewProp.prototype.toJSON = function() {
    var copy = ko.toJS(this);
    delete copy.__ko_mapping__;
    return copy;
};

(function (module, viewModel) {
    // VM_AddressesHeader
    viewModel.Header = new VM_AddressesHeader("b5f70c49-4fe2-4b29-86a4-2f97fc303ad0", "GetDetails");
    
    // VM_AdressesStructure
    viewModel.Addresses = ko.observableArray();

    // ValuesHelps
    viewModel.AddressTypes = ko.observableArray();
    
    viewModel.Property = null;
    
    // Global Actions
    viewModel.GetDetails = function () {
        ExecuteCmd('GetDetails', Module.AddressModel, AddressesCallback); 
    };
})(Module = window.Module || {}, Module.AddressModel = window.Module.AddressModel || {});

Module.AddressModel.Add = function () {
   ...