knocout bootstrap popover with templating
by Keyur Patel
HTML
<script src="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.0/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css">
<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.debug.js"></script>
<!doctype html>
<html>
<body>
<div data-bind="foreach: items">
<span data-bind="text: label"></span>
<input type="checkbox" data-bind="checked: required" />
<button data-bind="popover: 'settingsPopover'">settings</button>
<br />
</div>
<script type="text/html" id="settingsPopover">
<h4> <span class="icon-cog"> </span> Attributes</h4> <label> Label </label>
<input type="text" data-bind="value: label, valueUpdate:'afterkeydown'" /> <label class = "checkbox" > <input type="checkbox" data-bind="checked: required" />Required</label>
</script>
</body>
</html>
JavaScript
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
};
function guid() {
return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
}
ko.bindingHandlers.withProperties = {
init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
// Make a modified binding context, with a extra properties, and apply it to descendant elements
var newProperties = valueAccessor(),
innerBindingContext = bindingContext.extend(newProperties);
ko.applyBindingsToDescendants(innerBindingContext, element);
// Also tell KO *not* to bind the descendants itself, otherwise they will be bound twice
return { controlsDescendantBindings: true };
}
};
// Bind Twitter Popover
ko.bindingHandlers.popover = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var tmplId = ko.utils.unwrapObservable(valueAccessor());
var tmplHtml = $('#' + tmplId).html();
var uuid = guid();
var domId = "ko-bs-popover-" + uuid;
var tmplDom = $('<div/>', {
"class": "ko-popover",
"id": domId,
"data-bind": "withProperties: { label: '" + viewModel.label() + "', required: '" + viewModel.required() + "' }"
}).html(tmplHtml);
options = {
content: tmplDom[0].outerHTML
};
// Need to copy this, otherwise all the popups end up with the value of the last item
var popoverOptions = $.extend({}, ko.bindingHandlers.popover.options);
popoverOptions.content = options.content;
console.log($(element));
console.log(element);
$(element).bind('click', function () {
$(this).popover(popoverOptions).popover('toggle');
// If you apply this when the popup isn't visible, I think that it tries to bind to thewhole pageand throws an error
...