JSFiddle - React, Tailwind, and code Playground

by manchagnu

HTML

<script src="http://knockoutjs.com/downloads/knockout-2.2.1.js"></script>
<script src="https://raw.github.com/SteveSanderson/knockout.mapping/master/build/output/knockout.mapping-latest.debug.js"></script>
<div class="treeContainer">
    <div data-bind="text: name"></div><button class='loadData'>Load data</button>
    <!-- ko template: {name: 'items', data: $data} -->
    <!-- /ko -->
</div>

<script id='items' type="text/x-template">
    <ul data-bind="foreach: items">
        <li class="collapsed">
            <button class="expander"></button><span data-bind="text: name"></span>
            <!-- ko if: hasDetails -->
                <ul class="details">
                    <li data-bind="text: properties.description"></li>
                    <li data-bind="text: properties.date"></li>
                </ul>
            <!-- /ko -->
        </li>
    </ul>
</script>

CSS

ul {
    list-style-type: none;    
}

li.collapsed > ul {
   display: none;     
}

ul .details {
    border: 1px solid grey;
    padding-left: 20px;
}

button.expander {
}

li.collapsed button:after {
    content: "+"
}

li button:after {
    content: "--" 
}

JavaScript

var viewModel = (function(){
    var model = {
        name: "My Tree",
        items: []
    };

    var mapping = {
        items: {
            create: function (options) {
                options.data.properties = {
                    description: ko.observable(""),
                    date: ko.observable("")
                };
                
                options.data.hasDetails = false;
                
                /*
                options.data.hasDetails = ko.computed(function(){
                      return options.data.properties.description().length || options.data.properties.date().length;
                });
                */
                
                return ko.mapping.fromJS(options.data);
            }
        }
    };

    var _viewModel = ko.mapping.fromJS(model, mapping);
    return _viewModel;    
})();


ko.applyBindings(viewModel, $('.treeContainer')[0]);


var _server = (function(){
    var _itemsDetails = {
        1: {
            description: "This is my first test",
            date: new Date()
        },
        2: {
            description: "This is my second descrition",
            date: new Date()
        }
    };

    function findItemById( id ) {
        var item = _itemsDetails[id];
        
        if (!item){
            throw "Item not found";
        }
    
        return item;
    };

    function loadItems () {
        var deferred = $.Deferred();
    
        setTimeout(function() {
            var model = {
                items:[{
                    id: 1,
                    name: "item 1"
                }, {
                    id: 2,
                    name: "item 2"   
                }]
            };
            
            deferred.resolve(model);
        }, 2000 );
    
        return deferred.promise();
    };        
    
    function loadItemDetails(data){
        var deferred = $.Deferred();
        
        setTimeout(function() {
            var item;
            try {
                ...