I've found a couple other questions and resources here on using Bootstrap tooltips with a custom knockout binding handler. However, I haven't found is a cohesive solution that 1) involves using a dynamic knockout template 2) one where the tooltip can change when data it is bound to changes.
I'm also away of knockout-bootstrap on GitHub, but the tooltip title in that is rendered only once,
I've created a NEW JSFiddle with the following new dynamicTooltip that's based on the prior JSFiddle .
The new DynamicTooltip data binder looks like:
ko.renderTemplateHtml = function (templateId, data) {
var node = $("<div />")[0];
ko.renderTemplate(templateId, data, {}, node);
return $(node).html();
};
ko.bindingHandlers.tooltip = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var local = ko.utils.unwrapObservable(valueAccessor()),
options = {};
ko.utils.extend(options, ko.bindingHandlers.tooltip.options);
ko.utils.extend(options, local);
var tmplId = options.kotemplate;
ko.utils.extend(options, {
title: ko.renderTemplateHtml(tmplId, viewModel)
});
$(element).tooltip(options);
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).tooltip("destroy");
});
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var local = ko.utils.unwrapObservable(valueAccessor()),
options = {};
ko.utils.extend(options, ko.bindingHandlers.tooltip.options);
ko.utils.extend(options, local);
var tmplId = options.kotemplate;
var forceRefresh = options.forceRefresh;
var newdata = ko.renderTemplateHtml(tmplId, viewModel);
$(element).data('bs.tooltip').options.title = newdata
},
options: {
placement: "top",
trigger: "hover",
html: true
}};
It's not complete, as I'm manually triggering the update call manually by passing in a dummy databinding property on the view Model, in this case, it's called renderTooltip():
<a data-bind="tooltip: { title: firstName, placement: 'bottom', kotemplate: 'tile-tooltip-template', forceRefresh: renderTooltip() }">Hover on me</a>
I'd like to be able to trigger the tooltip to refresh itself when data changes.
I'm thinking I should be using createChildContext() and maybe controlsDescendantBindings, but I'm not really sure.
Any thoughts? I'll continue to update this, because it seems like dynamic bootstrap tooltips would be a common idea.
The root of the problem is that the update binding isn't firing, because it doesn't have a dependency on the properties that you are trying to update (ie firstName and address);
Normally you can delegate these properties to a new binding and let knockout automatically handle the dependency tracking. However, in this case, you're actually returning a string, so the element's automatic binding can't be used. A string is necessary, because that's how the tooltip works. If it could dynamically read from a DOM element, then the automatic bindings would work, but because it requires a HTML string, there's no way for the bindings to affect that.
Couple of options that I see:
1. Automatically create a dependency on the properties used by the template. This can be done by isolating the template view model (data) as seen in this fiddle: http://jsfiddle.net/tMbs5/13/
//create a dependency for each observable property in the data object
for(var prop in templateData)
if( templateData.hasOwnProperty(prop) && ko.isObservable(templateData[prop]))
templateData[prop]();
2. Instead of using an DOM-based template, use ko.computed to generate the template inside your view model. This will automatically create the dependencies as needed. See this fiddle for an example of that: http://jsfiddle.net/tMbs5/12/
var vm = {
firstName: ko.observable('Initial Name'),
address: ko.observable('55 Walnut Street, #3'),
changeTooltip: function () {
this.firstName('New Name');
}
};
vm.tooltipHtml = ko.computed(function () {
return "<h2>" + vm.firstName() + "</h2>" +
"<span>" + vm.address() + "</span>";
});
ko.applyBindings(vm);
note: In both fiddles, I have refactored things a tiny bit - mostly for simplification
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.