JSFiddle - React, Tailwind, and code Playground

by Kevin Van Lierde

HTML

<script src="https://code.jquery.com/jquery-1.11.2.js"></script>
<script src="http://knockoutjs.com/downloads/knockout-3.2.0.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
<select class="form-control" data-bind="options: persons, optionsText: 'name', value:editingPerson, optionsCaption: '-- Select one --'""></select>
<div data-bind="with:editingPerson">
    id: <input data-bind="value:id"> <br>      
    name: <input data-bind="value:name"> <br>
    surname: <input data-bind="value:surname"> <br>
    Full Name: <input data-bind="value:fullName"> <br>
    Address: <input data-bind="value:address.fullAddress"> <br>
    <table>
        <thead>
            <tr>
                <td>price</td>
                <td>iva</td>
                <td>tax</td>
            </tr>
        </thead>
        <tbody data-bind="foreach:amounts">
            <tr>
                <td data-bind="text:price"></td>
                <td data-bind="text:iva"></td>
                <td data-bind="text:tax"></td>
            </tr>
        </tbody>
    </table>
            <button data-bind="click:$root.savePerson" type="button">Save</button>
</div>


<textarea data-bind="value:ko.toJSON($root)" cols="100"></textarea>

JavaScript

function Person(options){
    var self = this, mapping = {
        'amounts': { create: function(options) { return new Amount(options.data); }},
        'address': { create: function(options) { return new Address(options.data); }}
    };  
    ko.mapping.fromJS(options, mapping, self);
    self.fullName   = ko.computed(function() {
        return self.name()+" - "+self.surname();
    });  
}
function Address(options){
    var self = this;
    ko.mapping.fromJS(options, {}, self);
    self.fullAddress    = ko.computed(function() {                                          
        return self.street()+" - "+self.number();
    });
}
function Amount(options){
    var self = this;
    ko.mapping.fromJS(options, {} ,self);
    self.tax    = ko.computed(function() {
         var t = parseInt(self.iva()) * parseInt(self.price());   
         return self.iva() && self.price() ? t.toString() : false;
    }); 
}

function PersonViewModel() {
    var self = this,
        mapping = {'persons': { create: function(options) { return new Person(options.data);}}};
    self.editingPerson = ko.observable();
    self.savePerson = function() {
        alert(ko.toJSON(self.editingPerson));        
    };

    self.Init = function() {    
//        $.getJSON("persons.php", function(allData) {                        
//            ko.mapping.fromJS(allData, mapping,self.persons);
//        });
// simulate some data coming back from an ajax request
 ko.mapping.fromJS({"persons": [{"id":1,"name":"name of p1","surname":"surname p1","address":{"id":1,"street":"street example","number":"#647"},"amounts":[{"id":2,"price":34,"iva":21},{"id":3,"price":35,"iva":21}]},{"id":2,"name":"name of p2","surname":"surname p2","address":{"id":12,"street":"street example 2","number":"#757"},"amounts":[{"id":22,"price":56,"iva":21},{"id":13,"price":45,"iva":21}]}]}, mapping,this);
    };
}

     var viewModel = new PersonViewModel();
     viewModel.Init();
     ko.applyBindings(viewModel);