Explanation
Is that an complex example? Don't worry, I will explain you step by step. It'll take you 5-10 minutes to get it.
First of all, add a list of seat reservations without any behaviours.
// Class to represent a row in the seat reservations grid
function SeatReservation(name, initialMeal) {
var self = this;
self.name = html.data(name);
self.meal = html.data(initialMeal);
self.formattedPrice = html.data(function() {
var price = self.meal().price;
return price ? "$" + price.toFixed(2) : "None";
});
}
//Viewmodel for the page, along with initial state
function ReservationsViewModel() {
var self = this;
// 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 = html.data([
new SeatReservation("Steve", self.availableMeals[0]),
new SeatReservation("Bert", self.availableMeals[1])
]);
}
var vm = new ReservationsViewModel();
And here is the rendering code (aka the View in MVVM)
html('#meal-reservation table tbody').each(vm.seats, function(seat, index){
html.tr()
.td().input(seat.name).clss('form-control input-w160').$().$()
.td()
.dropdown(vm.availableMeals, seat.meal, 'mealName').clss('form-control input-w210 margin5').$()
.$()
.td().span(seat.formattedPrice).$().$()
.td().button('Remove').clss('btnViolet').$().$()
.$()
});
Well done! You got a meal reservation list with initial values.
And there are some parts of the code will make you confuse. You may ask what is the .$() and why use that. Is that sort of jQuery method? Of course, no jQuery here.
This framework doesn't depend on any library.
The answer is that is the function to indicate that you have nothing more to do in a DOM element. For example, you can add class, add event click on an input or event add a child element.
After doing those things, you want to render another control. Then you must tell the framework in somehow append another control into the parent node.
So the role of $ method is just exactly like the role of end tag in HTML code. And therefore,
br() method wouldn't end up with
$().
One more thing is dropdown method. It is built-in control for simple select tag. It takes 4 parameters as following.
1. An observed array (availableSeats in this case).
2. Current value of the list.
3. (Optional) Display field in each object representing an option.
4. (Optional) Value field in each object representing an option.
Now you will add some computed properties like total surcharge and total discount.
Add to ReservationsViewModel the following code:
function ReservationsViewModel() {
//...previous code
// Computed data
self.totalSurcharge = html.data(function() {
var total = 0;
for (var i = 0; i < self.seats().length; i++)
total += self.seats()[i].meal().price;
return total.toFixed(2);
});
self.totalDiscount = html.data(function() {
return (self.totalSurcharge()*90/100).toFixed(2);
});
self.seatNum = html.data(function(){
return self.seats().length;
});
}
And you bind those data to the View.
//...previous code
html('#seatNumber').text(vm.seatNum);
html('#surcharge').text(vm.totalSurcharge);
html('#discount').text(vm.totalDiscount);
Now you got some useful information numbers from the list.
If you want that these numbers to be live updated. Then you need to add some behaviours like "Add" or "Remove".
The code in View-Model.
function ReservationsViewModel() {
//...previous code
// Operations
self.addSeat = function() {
self.seats.add(new SeatReservation("", self.availableMeals[0]));
};
self.removeSeat = function(e, seat) {
self.seats.remove(seat);
};
}
You need to bind those events to the View.
//...previous code
html('#addSeat').click(vm.addSeat).refresh(vm);
//...previous code
//.td().span(seat.formattedPrice).$().$()
.td().button('Remove').clss('btnViolet').click(vm.removeSeat, seat).refresh(vm).$().$()
What does refresh mean in the code? It is a method for refresh any kind of computed properties in view-model after a change or click event.
Why do you need that method? Because you have too many dependencies need to be refreshed, and those dependencies maybe too weak for the framework to know.
For example some of seats are added at runtime by user, how can you declare dependencies without its reference at coding time.
Or you simply don't want to declare too many dependencies (you may have hundred of them in real world application). So all you need to do is add refresh method.
Just a little more. Add refresh method after dropdown control to refresh data when changing selected item.
//...previous code
//.td()
.dropdown(vm.availableMeals, seat.meal, 'mealName').refresh(seat, vm).$()
//$()
//...