ArrayArray

Testing array within array

HTML

<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/2.3.0/knockout-min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.3.5/knockout.mapping.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout-validation/1.0.2/knockout.validation.min.js"></script>
<script src="https://rawgithub.com/rniemeyer/knockout-sortable/master/build/knockout-sortable.js"></script>
Action items:
<a href="#" data-bind="click: loadData">Load from storage</a> 
<a href="#" data-bind="click: saveData">Save to storage</a> 
<a href="#" data-bind="click: clearData">Clear data</a> 
<a href="#" data-bind="click: saveDataToInput">Save to inputbox</a> 
<a href="#" data-bind="click: checkValid">Check is valid</a>

<br/>
<br/>Sales person name:
<input data-bind="value:FullName" />
<br/>Regions:
<br/>
<br/>
<a href="#" data-bind="click: addRegion">Region +</a>  <a href="#" data-bind="click: addCustomer">Customer +</a>

<div data-bind="sortable:Regions">
    <div class="Regionbox">Region:
    <input data-bind="value:Name" /> <a href="#" data-bind="click: $parent.removeRegion">x</a> 
    </div>
    
</div>

<br />
<div data-bind="sortable:Customers">
    <div class="Customerbox">
    Customer:
    <input data-bind="value:Name" /> <a href="#" data-bind="click: $parent.removeCustomer">x</a>
 <a href="#" data-bind="click: addOrder">Order +</a> 
    <br />
    <div data-bind="foreach:Orders">---- Order date:
        <input data-bind="value:Date" />Value:
        <input data-bind="value:Value" /> <a href="#" data-bind="click: $parent.removeOrder">x</a> 
        <br />
    </div> <!-- foreach Orders -->
    </div>
</div> <!-- foreach Customer -->

<div>
    <hr>for clipboard:
        <textarea id="clip" value="" cols="50" rows="10"></textarea>
</div>
        
        
<br />
<hr />
<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>

CSS

.errorCSS {
    border:1px solid red;
    background-color: #FFFF00;
}

.Regionbox {
    border:1px solid gray;
    background-color: #fdd;
    padding:5px;
    cursor: move;
    width:200px;
    padding: 5px;
    margin: 5px;
}

.Customerbox {
    border:1px solid gray;
    background-color: #C0C0C0;
    padding:5px;
    cursor: move;
    width:600px;
    padding: 3px;
    margin: 3px;    
}

JavaScript

// setup defaults for validation
var validationOptions = {
    insertMessages: true,
    decorateElement: true,
    errorElementClass: 'errorCSS',
    messagesOnModified: true,
    debug: true,
    grouping: {
        deep: true,
        observable: false //Needed so added objects AFTER the initial setup get included
    },
};

ko.validation.init(validationOptions);

var Region = function (data) {
    var self = this;
    if (data != null) {
        ko.mapping.fromJS(data, {}, self); 
    } else {
        self.ID = ko.observable();
        self.Name = ko.observable().extend({
            required: true
        });
    }

    self.Name.extend({
        required: {
            message: '* Name needed'
        }
    });
}

var Customer = function (data) {
    var self = this;
    if (data != null) {
        ko.mapping.fromJS(data, {}, self);
    } else {
        self.ID = ko.observable();
        self.Name = ko.observable().extend({
            required: true
        });
        self.Orders = ko.observableArray(); // array of Orders
    }

    // operations
    self.addOrder = function () {
        self.Orders.push(new Order({
            ID: null,
            Date: "",
            Value: ""
        }));
    }
    self.removeOrder = function (Order) {
        self.Orders.remove(Order);
    }

    self.Name.extend({
        required: {
            message: '* Name needed'
        }
    });
}

var Order = function (data) {
    var self = this;
    if (data != null) {
        ko.mapping.fromJS(data, {}, self); // in brackets need the mapping function to pass
    } else {
        self.ID = ko.observable();
        self.Date = ko.observable().extend({
            required: true
        });
        self.Value = ko.observable().extend({
            required: true
        });
    }
    self.Value.extend({
        required: {
            message: '* Value needed'
        }
    });
}

// define view model
var SalesPerson = function (data) {
    var self = this;
    if (data...