I am trying to use "virtual element" with html binding to create html part on the fly but failed with message: "The binding 'html' cannot be used with virtual elements". Here is the jsfiddle: http://jsfiddle.net/d3Dpp/.
Anyone knows if there is any workaround?
Well, after some playing with knockout I see that it is possible.
Working example is here
http://jsfiddle.net/d3Dpp/42/
unfortunatelly this requires duplication of some internal knockout functionality
UPDATE
KnockoutJS 2.2.1 added virtual elements binding to export, so it is available even in minified version:
ko.exportSymbol('virtualElements.allowedBindings', ko.virtualElements.allowedBindings);
It means that better solution for html binding is possible - see Martijn's answer.
Based on Artem's code and KnockoutJS 2.2.1, here's an improved version:
http://jsfiddle.net/YZzDe/2/
Improvements:
- Less code, less duplication (hooks in to exposed interfaces)
- Overrides 'html' binding, so basically the old 'html' can now be used in virtuals
- No more global functions.
Here's the code
{
var overridden = ko.bindingHandlers['html'].update;
ko.bindingHandlers['html'].update = function (element, valueAccessor) {
if (element.nodeType === 8) {
var html = ko.utils.unwrapObservable(valueAccessor());
ko.virtualElements.emptyNode(element);
if ((html !== null) && (html !== undefined)) {
if (typeof html !== 'string') {
html = html.toString();
}
var parsedNodes = ko.utils.parseHtmlFragment(html);
if (parsedNodes) {
var endCommentNode = element.nextSibling;
for (var i = 0, j = parsedNodes.length; i < j; i++)
endCommentNode.parentNode.insertBefore(parsedNodes[i], endCommentNode);
}
}
} else { // plain node
overridden(element, valueAccessor);
}
};
}
ko.virtualElements.allowedBindings['html'] = true;
You could also use this as your view:
<div data-bind="html: html"></div>
This will replace the innerHtml of the div "container" with your provided html property.