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 class="container">
    <div data-bind="safeTemplate: { name: 'AddressEntry', data: Addresses()[0] }"></div>
    <div data-bind="safeTemplate: { name: 'AddressEntry', data: Addresses()[2] }"></div>
</div>

<div class="container">
    <div data-bind="safeTemplate: { name: 'AddressEntry', data: Addresses()[1] }"></div>
    <div data-bind="safeTemplate: { name: 'AddressEntry', data: Addresses()[3] }"></div>
</div>

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

<script id="AddressEntry" type="text/html">
    <div class="entry">
        {{if $item.check }}
            <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: 'Value'
                    "
                ></select>
            </div>
            <div...

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 5px #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 {
    border: 1px solid black;
    margin: 2px;
    padding: 5px;
    background: #ccc;
    font-family: monospace;
}

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 = AddressModel.Header;

    this.GUID = '';
    this.AddressType = '';
    this.Lastname = '';
    this.Firstname = '';
    this.City = '';
    
    ko.mapping.fromJS(data, {}, this);
    
    // ValueHelps References
    this.AddressTypes = 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;
};

var AddressModel = {
    // VM_AddressesHeader
    Header: new VM_AddressesHeader("b5f70c49-4fe2-4b29-86a4-2f97fc303ad0", "GetDetails"),
    
    // VM_AdressesStructure
    Addresses: ko.observableArray(),

    // ValuesHelps
    AddressTypes: ko.observableArray(),
    
    // Global Actions
    GetDetails: function () {
        ExecuteCmd('GetDetails', AddressModel, AddressesCallback); 
    },
};

AddressModel.Add = function () {
    this.Addresses.push(new VM_AddressesStructure ());
}.bind(AddressModel);

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

var first = true;

function AddressesCallback(viewModel, data) {
    
    if (first) {
        var mapping = {
            'Addresses' : {
                create: function (options) {
                    return new VM_AddressesStructure (options.data);
                },
                key: function (data) {
    ...