Knockout.JS Tutorials
Point alloting
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">
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script src="https://jquery-star-rating-plugin.googlecode.com/svn/trunk/jquery.rating.js"></script>
<link rel="stylesheet" href="https://jquery-star-rating-plugin.googlecode.com/svn/trunk/jquery.rating.css">
<link rel="stylesheet" href="http://learn.knockoutjs.com/Content/TutorialSpecific/custombindings.css">
<h3 data-bind="text: question"></h3>
<p>Please distribute <b data-bind="text: pointsBudget" class="blue status"></b> points between the following options.</p>
<table class="table">
<thead>
<tr>
<th>Factors</th>
<th>Importance</th>
</tr>
</thead>
<tbody data-bind="foreach: answers">
<tr>
<td data-bind="text: answerText"></td>
<td data-bind="starRating: points"></td>
</tr>
</tbody>
</table>
<p><strong>You've got <span data-bind="text: pointsBudget - pointsUsed(), css: updateClass" class="status"></span> points left to use.</strong></p>
<h3 data-bind="fadeVisible: pointsUsed() > pointsBudget">You have alloted <span class="red" data-bind="text: pointsUsed() - pointsBudget"></span> extra point<span data-bind="visible: (pointsUsed() - pointsBudget) > 1">s</span>! Please remove some.</h3>
<button data-bind="jqButton: {enable: pointsUsed() <= pointsBudget}, click: save">Finished</button>
CSS
body {
padding:10px 5px;
}
.table {
background-color: #cfdfff;
margin: 15px 0!important;
}
.table,
.table > thead > tr > th {
border:2px solid #abe!important;
border-width: 1px 0!important;
}
.table > tbody > tr > td,
.table > tbody > tr > th {
border:1px solid rgba(255,255,255, 0.2)!important;
border-width: 1px 0!important;
}
.blue {
color: #080;
}
.red {
color: #c33;
}
.status {
background-color: #ddd;
padding: 0 5px;
}
.ui-state-disabled {
opacity:0.5!important;
}
.hoverChosen:not(.chosen) {
opacity:0.6;
}
JavaScript
// --------------------------------------------------------------
// Reusable bindings - ideally kept in a separate file
ko.bindingHandlers.fadeVisible = {
init: function(element, valueAccessor) {
var shouldDisplay = valueAccessor();
$(element).toggle(shouldDisplay);
},
update: function(element, valueAccessor) {
var shouldDisplay = valueAccessor();
shouldDisplay ? $(element).fadeIn() : $(element).fadeOut();
}
};
ko.bindingHandlers.jqButton = {
init: function(element) {
$(element).button();
},
update: function(element, valueAccessor) {
var currentValue = valueAccessor();
$(element).button("option", "disabled", currentValue.enable === false);
}
};
ko.bindingHandlers.starRating = {
init: function(element, valueAccessor) {
$(element).addClass("starRating");
for (var i = 0; i < 5; i++)
$("<span>").appendTo(element);
$("span", element).each(function(index) {
$(this)
.hover(function() {
$(this).prevAll()
.add(this)
.toggleClass("hoverChosen")
})
.click(function() {
var observable = valueAccessor();
observable(index+1);
});
});
},
update: function(element, valueAccessor) {
var observable = valueAccessor();
$("span", element).each(function(index) {
$(this).toggleClass("chosen", index < observable());
});
}
};
// --------------------------------------------------------------
// Page viewmodel
function Answer(text) {
this.answerText = text; this.points = ko.observable(1);
}
function SurveyViewModel(question, pointsBudget, answers) {
this.question = question;
this.pointsBudget = pointsBudget;
this.answers = $.map(answers, function(text) {
return new Answer(text)
});
this.save = function() { alert('You are...