JSFiddle - React, Tailwind, and code Playground

by kwon

HTML

<script src="http://cloud.github.com/downloads/SteveSanderson/knockout/knockout-2.0.0.js"></script>
<script src="https://raw.github.com/SteveSanderson/knockout.mapping/master/build/output/knockout.mapping-latest.js"></script>
<!-- ko with: restaurant_menu_view -->
<h1>Menus For <span data-bind="text: restaurant.name"></span></h1>

<button data-bind="click: restaurant.new_menu_type">New MenuType</button>

<div class="clear"></div>

<div class="righty">
<ol data-bind='foreach: restaurant.menu_types'>
    <li>
        <article>
            <h1 data-bind="text: name"></h1>
            <nav data-bind="visible: id">
                <a href="#" data-bind="click: new_menu_category">Add New Cateogry</a>
                &nbsp; | &nbsp;
                <a href="#" data-bind="click: $parent.restaurant.remove_menu_type">X</a>
            </nav>
            
            <ol data-bind="foreach: menu_categories, visible: menu_categories().length > 0">
                <li>
                    <article>
                        <h1 data-bind="text: name"></h1>
                        <nav>
                            <a href="#" data-bind="click: new_menu_item">Add New Item</a>
                            &nbsp; | &nbsp;
                            <a href="#" data-bind="click: $parent.remove_menu_category">X</a>
                        </nav>
                        
                        <ol data-bind="foreach: menu_items, visible: menu_items().length > 0">
                            <li>
                                <article>
                                    <h1 data-bind="text: name"></h1>
                                    <nav>
                                        <a href="#" data-bind="click: $parent.remove_menu_item">X</a>
                                    </nav>
                                </article>
                            </li>
                        </ol>
                    </article>
                </li>
            </ol>
        </article>
  ...

SCSS

ol {
    list-style-type: decimal;
    margin: 5px 25px;
}

.clear {
    clear: both;
}

.righty {
    float: left;
    width: 50%;
    height: 350px;
    overflow-y: auto;
}

.lefty {
    background-color: #efefef;
    float: left;
    width: 50%;
}

JavaScript

var SampleData = {
    restaurant: {
        name: "Taggia",
        
        menu_types: [
            {
                id: 123,
                name: "Lunch",
                seo_title: "Lunch",
                seo_description: "What you usually eat around noon",
                
                menu_categories: [
                    {
                        name: "Main",
                        seo_title: "Main",
                        seo_description: "lorem ipsum dolor ist amen",
                        description: "Whatever...",
                        
                        menu_items: [
                            {
                                name: "Juice",
                                price: "1000.00",
                                description: "That is some kind of juice"
                            }                                
                        ]
                    }   
                ]
            }
        ]
    }
};



var MenuItemViewModel = function(data) {
    this.id = ko.observable();
    this.menu_category_id = ko.observable();
    
    ko.mapping.fromJS(data, {}, this);
};

var MenuCategoryViewModel = function(data) {
    this.id = ko.observable();
    this.menu_item_id = ko.observable();
    
    this.name = ko.observable();
    this.menu_items = ko.observableArray([]);
    
    var mapping = {
        'menu_items': {
            create: function(options) {
                console.log(options.data);
                return new MenuItemViewModel(options.data);
            }
        }
    };
    ko.mapping.fromJS(data, mapping, this);
    
    var self = this;
    self.new_menu_item = function() {
        if (!MenuItemFormView.visible()) {
            ko.mapping.fromJS({menu_category: self, name: "", visible: true}, {},
                              MenuItemFormView);
        }
    },
    self.add_menu_item = function(data) {
        self.menu_items.push(new MenuItemViewModel(data));
       ...