我正在尝试为引用模板的twitter boostrap popover创建一个自定义绑定,但是一旦创建了弹出窗口内容的绑定部分我就遇到了问题.
我之前已经看到过这个问题,但我觉得它们大部分都非常混乱,而且我非常接近使用模板的可重用解决方案.
http://jsfiddle.net/billpull/Edptd/
// 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 }).html(tmplHtml); options = { content: tmplDom[0].outerHTML }; var popoverOptions = ko.utils.extend(ko.bindingHandlers.popover.options,options); console.log($(element)); console.log(element); $(element).bind('click',function () { $(this).popover(popoverOptions).popover('toggle'); ko.applyBindings(bindingContext,document.getElementById(domId)); }); },options: { placement: "right",title: "",html: true,content: "",trigger: "manual" } };
===编辑
基于下面的答案更新了代码,允许您在没有额外的withProperties绑定的情况下执行此操作
// Bind Twitter Popover ko.bindingHandlers.popover = { init: function(element,bindingContext) { // read popover options var popoverBindingValues = ko.utils.unwrapObservable(valueAccessor()); // set popover template id var tmplId = popoverBindingValues.template; // set popover trigger var trigger = popoverBindingValues.trigger; // get template html var tmplHtml = $('#' + tmplId).html(); // create unique identifier to bind to var uuid = guid(); var domId = "ko-bs-popover-" + uuid; // create correct binding context var childBindingContext = bindingContext.createChildContext(viewmodel); // create DOM object to use for popover content var tmplDom = $('<div/>',"id" : domId }).html(tmplHtml); // set content options 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; // bind popover to element click $(element).bind(trigger,function () { $(this).popover(popoverOptions).popover('toggle'); // if the popover is visible bind the view model to our dom ID if($('#' + domId).is(':visible')){ ko.applyBindingsToDescendants(childBindingContext,$('#' + domId)[0]); } }); return { controlsDescendantBindings: true }; },trigger: "manual" } };
解决方法
你需要用我的老朋友
custom bindings.
ko.bindingHandlers.withProperties = { init: function(element,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 }; } };
然后,您需要将data-bind属性添加到您正在生成的html中:
var tmplDom = $('<div/>',{ "class": "ko-popover","id": domId,"data-bind": "withProperties: { label: '" + viewmodel.label() + "',required: '" + viewmodel.required() + "' }"
我把jsFiddle放在一起显示了这一点.有几个陷阱,我不得不为每个弹出窗口复制弹出框选项,否则它们最终都会得到最后一组值.
var popoverOptions = $.extend({},ko.bindingHandlers.popover.options); popoverOptions.content = options.content;
而且我还必须在弹出窗口应用绑定时才显示,否则它似乎试图绑定到整个页面.
$(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 if($('#' + domId).is(':visible')) { ko.applyBindings(viewmodel,$('#' + domId)[0]); } });
这似乎也是双向的,因为你可以更改弹出窗口中的值并更新非弹出元素,但我不会说谎,我没想到会发生这种情况!