Knockout.JS Tutorials

Reserva de Asientos

by Marventus

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-debug.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<h2>Reserva de Asientos (<span data-bind="text: seats().length"></span>)</h2>

<table class="table">
    <thead><tr>
        <th>Nombre del<br/>pasajero</th>
        <th>Comida</th>
        <th>Recargo</th>
        <th></th>
    </tr></thead>
    <tbody data-bind="foreach: seats">
        <tr>
            <td><input data-bind="value: name" /></td>
            <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">Eliminar</a></td>
        </tr>   
    </tbody>
</table>

<button data-bind="click: addSeat, enable: seatLimit() < 5" class="btn btn-primary">Reserve otro asiento</button>

<h3 data-bind="visible: totalSurcharge() > 0">
    Recargo total: $<span data-bind="text: totalSurcharge().toFixed(2)"></span>
</h3>

CSS

table {
    width: 100%;
}
table td,
table th{
    padding: 5px;
    text-align:center;
}
h2 span {
    color:#337ab7;
}

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) : "0" );        
    });
}

// Overall viewmodel for this screen, along with initial state
function ReservationsViewModel() {
    var self = this;
    self.viewers = ["Steve", "Bert", "John"];

    // Non-editable catalog data - would come from the server
    self.availableMeals = [
        { mealName: "Standard (sandwich)", price: 0 },
        { mealName: "Premium (lobster)", price: 34.95 },
        { mealName: "Ultimate (whole zebra)", price: 290 }
    ];    

    // Editable data
    self.seats = ko.observableArray();
    for(i=0; i<self.viewers.length; i++) {
        self.seats.push( new SeatReservation(self.viewers[i], self.availableMeals[0]) );
    }

    // Operations
    self.addSeat = function() {
        self.seats.push(new SeatReservation("", self.availableMeals[0]));
    }
    self.removeSeat = function(seat) {
        self.seats.remove(seat);
    }
    self.totalSurcharge = ko.computed(function() {
       var t = 0;
       for (var i = 0; i < self.seats().length; i++)
           t += self.seats()[i].meal().price;
       console.log(self.seats());
       return t;
    });
    self.seatLimit = function() {
        var block = self.seats().length >= 5 ? true : false,
            msg = "Ha excedido el número máximo de asientos (5) que puede reservar.";
        if( block )
            alert(msg);
        return self.seats().length;
    }
}

ko.applyBindings(new ReservationsViewModel());