JSFiddle - React, Tailwind, and code Playground

by aman1981

HTML

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.16/css/dataTables.bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.16/js/jquery.dataTables.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.16/js/dataTables.bootstrap.min.js"></script>
<h2>Your seat reservations (<span data-bind="text: seats().length"></span>)</h2>
<table>
    <thead>
        <tr>
            <th>Passenger Name</th>
            <th>Meal</th>
            <th>Amount ($)</th>
            <th></th>
        </tr>
    </thead>
    @*render a copy of seats child elements for each entry in the seats array*@
    <tbody data-bind="foreach: seats">
        <tr>
          <td data-bind="text: name"></td>
    @*update the view to make use of the formatted Price*@
          <td>
           <select data-bind="options: $root.availableMeals, value: meal, optionsText: 'mealName'"></select></td>
          <td data-bind="text: formattedPrice"></td>
          <td><a href="#" data-bind="click: $root.removeSeat">Remove</a></td>
        </tr>
    </tbody>
</table>
<button data-bind="click: addSeat, enable: seats().length < 3">Reserve Another Seat</button>
<h3 data-bind="visible: totalAmount() > 0">Total Amount: $<span data-bind="text: totalAmount().toFixed(2)"></span></h3>

JavaScript

// Class to represent a row in the seat reservations grid
function SeatReservation(name, initialMeal) {
    var self = this;
    self.name = name;
    self.meal = ko.observable(initialMeal);
    self.formattedPrice = ko.computed(function () {
        var price = self.meal().price;
        return price ? "$" + price.toFixed(2) : "None";
    });
}
// Overall viewmodel for this screen, along with initial state
function ReservationsViewModel() {
    var self = this;
    // Non-editable Meals data - would come from the server
    self.availableMeals = [
        { mealName: "Vegetarian Raw Meal", price: 10.52 },
        { mealName: "Vegetarian Vegan Meal", price: 34.95 },
        { mealName: "Fruit Platter Meal", price: 45.50 }
    ];
    // Editable data - seats Array
    self.seats = ko.observableArray([
        new SeatReservation("Sampath", self.availableMeals[0]),
        new SeatReservation("Lokuge", self.availableMeals[1])
    ]);
    // Computed Total amount
    self.totalAmount = ko.computed(function () {
        var total = 0;
        for (var i = 0; i < self.seats().length; i++)
            total += self.seats()[i].meal().price;
        return total;
    });
    // add seats
    self.addSeat = function () {
        self.seats.push(new SeatReservation("Chaminda", self.availableMeals[2]));
    };
    // remove seats
    self.removeSeat = function (seat) { self.seats.remove(seat); };
}
ko.applyBindings(new ReservationsViewModel());