Created
September 11, 2011 12:16
learn.knockoutjs.com pimped templates tutorial
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<h2>Your seat reservations (<span data-bind="text: seats().length"></span>)</h2> | |
<table> | |
<thead><tr> | |
<th>Passenger name</th><th>Meal</th><th>Surcharge</th><th></th> | |
</tr></thead> | |
<tbody data-bind="template: {name:'reservationTemplate', foreach: seats}"></tbody> | |
</table> | |
<script type="text/x-jquery-tmpl" id="reservationTemplate"> | |
<tr> | |
<td><input data-bind="value: name" /></td> | |
<td><select data-bind="options: availableMeals, value: meal, optionsText: 'mealName'"></select></td> | |
<td data-bind="text: formattedPrice"></td> | |
<td><a href="#" data-bind="click: remove">Remove</a></td> | |
</tr> | |
</script> | |
<h3 data-bind="visible: totalSurcharge() > 0"> | |
Total surcharge: $<span data-bind="text: totalSurcharge().toFixed(2)"></span> | |
</h3> | |
<button data-bind="click: addSeat, enable: seats().length < 5">Reserve another seat</button> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Raw catalog data - would come from the server | |
var availableMeals = [ | |
{ mealName: "Standard (sandwich)", price: 0 }, | |
{ mealName: "Premium (lobster)", price: 34.95 }, | |
{ mealName: "Ultimate (whole zebra)", price: 290 } | |
]; | |
// Class to represent a row in the reservations grid | |
var seatReservation = function(name) { | |
this.name = name; | |
this.availableMeals = availableMeals; | |
this.meal = ko.observable(availableMeals[0]); | |
this.formattedPrice = ko.dependentObservable(function() { | |
var price = this.meal().price; | |
return price ? "$" + price.toFixed(2) : "None"; | |
}, this); | |
this.remove = function() { viewModel.seats.remove(this) } | |
} | |
// Overall viewmodel for this screen, along with initial state | |
var viewModel = { | |
seats: ko.observableArray([ | |
new seatReservation("Steve"), | |
new seatReservation("Bert") | |
]), | |
addSeat: function() { | |
this.seats.push(new seatReservation()); | |
} | |
}; | |
viewModel.totalSurcharge = ko.dependentObservable(function() { | |
var total = 0; | |
for (var i = 0; i < this.seats().length; i++) | |
total += this.seats()[i].meal().price; | |
return total; | |
}, viewModel); | |
ko.applyBindings(viewModel); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<h2>Your seat reservations</h2> | |
<table> | |
<thead><tr> | |
<th>Passenger name</th><th>Meal</th><th>Surcharge</th><th></th> | |
</tr></thead> | |
<tbody id="seats"></tbody> | |
</table> | |
<p><button id="add-seat">Reserve another seat</button></p> | |
<div id="total-container"> | |
<p>Total seats: <span id="total-seats"></span></p> | |
<p>Total surcharge: <span id="total-surcharge"></span></p> | |
</div> | |
<script type="text/x-jquery-tmpl" id="reservationTemplate"> | |
{{each seats}} | |
<tr> | |
<td><input data-bind="value: name"></td> | |
<td><select data-bind="options: availableMeals, value: meal, optionsText: 'mealName'"></select></td> | |
<td data-bind="text: formattedPrice"></td> | |
<td><a href="#" data-bind="click: remove">Remove</a></td> | |
</tr> | |
{{/each}} | |
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @preserve Unobtrusive Knockout support library for jQuery | |
* | |
* @author Joel Thoms | |
* @version 1.1 | |
*/ | |
(function($) { | |
if (!$ || !$['fn']) throw new Error('jQuery library is required.'); | |
/** | |
* Private method to recursively render key value pairs into a string | |
* | |
* @param {Object} options Object to render into a string. | |
* @return {string} The string value of the object passed in. | |
*/ | |
function render(options) { | |
var rendered = []; | |
for (var key in options) { | |
var val = options[key]; | |
switch (typeof val) { | |
case 'string': rendered.push(key + ':' + val); break; | |
case 'object': rendered.push(key + ':{' + render(val) + '}'); break; | |
case 'function': rendered.push(key + ':' + val.toString()); break; | |
} | |
} | |
return rendered.join(','); | |
} | |
/** | |
* jQuery extension to handle unobtrusive Knockout data binding. | |
* | |
* @param {Object} options Object to render into a string. | |
* @return {Object} A jQuery object. | |
*/ | |
$['fn']['dataBind'] = $['fn']['dataBind'] || function(options) { | |
return this['each'](function() { | |
var opts = $.extend({}, $['fn']['dataBind']['defaults'], options); | |
var attr = render(opts); | |
if (attr != null && attr != '') { | |
$(this)['attr']('data-bind', attr); | |
} | |
}); | |
}; | |
})(jQuery); | |
// Raw catalog data - would come from the server | |
var availableMeals = [ | |
{ mealName: "Standard (sandwich)", price: 0 }, | |
{ mealName: "Premium (lobster)", price: 34.95 }, | |
{ mealName: "Ultimate (whole zebra)", price: 290 } | |
]; | |
// Class to represent a row in the reservations grid | |
var seatReservation = function(name) { | |
this.name = name; | |
this.availableMeals = availableMeals; | |
this.meal = ko.observable(availableMeals[0]); | |
this.formattedPrice = ko.dependentObservable(function() { | |
var price = this.meal().price; | |
return price ? "$" + price.toFixed(2) : "None"; | |
}, this); | |
var remove = function() {console.log(this.meal()); viewModel.seats.remove(this) }; | |
this.remove = $.proxy(remove,this); | |
} | |
$('#seats').dataBind({ template: "'reservationTemplate'"}); | |
$('#add-seat').dataBind({click: 'addSeat',enable: 'seats().length < 2'}); | |
$('#total-container').dataBind({visible: 'seats().length > 0'}); | |
$('#total-seats').dataBind({text: 'seats().length'}); | |
$('#total-surcharge').dataBind({text: 'totalSurcharge() > 0 ? "$"+totalSurcharge().toFixed(2) : "None"'}); | |
// Overall viewmodel for this screen, along with initial state | |
var viewModel = { | |
seats: ko.observableArray([ | |
new seatReservation("Steve"), | |
new seatReservation("Bert") | |
]), | |
addSeat: function() { | |
var name = prompt("What is the passengers name?", "") | |
this.seats.push(new seatReservation(name)); | |
}, | |
totalSurcharge: function() { | |
var total = 0; | |
for (var i = 0; i < this.seats().length; i++) | |
total += this.seats()[i].meal().price; | |
return total; | |
} | |
}; | |
ko.applyBindings(viewModel); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment