JSFiddle - React, Tailwind, and code Playground

by origineil

HTML

<h2>Pizza toppings (<span data-bind="text: selectedToppings().length"></span>)</h2>

<table class="table table-bordered">
    <thead>
        <tr>
            <th>Topping</th>
            <th>Number of units</th>
        </tr>
    </thead>
    <tbody data-bind="foreach: {data: selectedToppings, as: 'current'}">
        <tr>
            <td>
                <select data-bind="options: $root.toppingsFilter(current), value: current.topping, optionsCaption: 'Select...', optionsText: 'name'"></select>
            </td>
            <td>
                <input data-bind="value: num" />
            </td>
            <td><a href="#" data-bind="click: $root.removeTopping">Remove</a>
            </td>
        </tr>
    </tbody>
</table>
<button type="button" class="btn btn-primary" data-bind="click: addTopping, enable: selectedToppings().length < 5">Add another topping</button>
<button type="button" data-bind="click: debug">Debug</button>

JavaScript

ko.extenders.manager = function (target, option) {
    //console.log(option)

    if (option.topping) {
        ko.computed(function () {

            //console.log("Eval")
            //console.log(option.topping)
            var selection = ko.utils.arrayFirst(option.selected(), function (row) {
                if (!row.topping()) {
                    return false
                }
                return row.topping().name === option.topping.name;
            })

            target(selection ? true : false) 
        })
    }
    return target;
};

// Class to represent a possible topping
function Topping(name) {
    var self = this;
    self.name = name;
    // This will have other properties
}

// Class to represent a row in the grid
function ToppingRow(topping, num) {
    var self = this;
    self.topping = ko.observable(topping);

    self.topping.subscribe(function (nv) {
        console.log("New value ");
        console.log(nv)
    })
    self.num = ko.observable(num);

    self.toppingName = ko.computed(function () {
        return self.topping() ? self.topping().name : "";
    });
}

function ToppingsViewModel() {
    var self = this;

    // Non-editable catalog data - would come from the server
    self.toppings = ko.observableArray([
    new Topping("Mushroom"),
    new Topping("Pepperoni"),
    new Topping("Cheese"),
    new Topping("Olives"),
    new Topping("Chicken")]);

    // Editable data
    self.selectedToppings = ko.observableArray([
    new ToppingRow({}, 1)]);



    // Operations
    self.addTopping = function () {
        self.selectedToppings.push(new ToppingRow({}, 1));
    }

    self.disable = ko.computed(function () {})

    self.removeTopping = function (topp) {
        console.log(topp);
        self.selectedToppings.remove(topp)
    }
    
    self.toppingsFilter= function(current){
        var arr = self.toppings();
        
          return arr
        }
        
        
                                                      ...