2013-02-12 3 views
2

Я создал пользовательскую привязку для нокаута для twitter bootstrap popovers, и я использую это для отображения данных с двусторонней привязкой в ​​popover, но если размер содержимого отличается между каждым popover выравнивание выключенTwitter Bootstrap Popovers Misaligned с разным размером контента

http://jsfiddle.net/billpull/g6vH2/1

Я не уверен, что соответствующий код, чтобы разместить сообщение будет настолько плохо, просто опубликовать все, что проверить на скрипке для демонстрации.

HTML

<!doctype html> 
<html> 
    <body> 
     <br><br><br> 
     <div data-bind="foreach: items"> 
      <span data-bind="text: label"></span> 
      <input type="checkbox" data-bind="checked: required" /> 
      <button data-bind="popover: {template: 'settingsPopover', trigger: 'click'}">settings</button><br> 
     </div> 
     <script type="text/html" id="settingsPopover"> 
      <h4><span class="icon-cog">&nbsp;</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> 
      <ul data-bind="foreach: options"> 
       <li data-bind="text: $data"></li> 
      </ul> 
     </script> 
    </body> 
</html> 

JS

function s4() { 
    return Math.floor((1 + Math.random()) * 0x10000) 
      .toString(16) 
      .substring(1); 
}; 
function guid() { 
    return s4() + s4() + '-' + s4() + '-' + s4() + '-' + 
     s4() + '-' + s4() + s4() + s4(); 
} 

// Bind Twitter Popover 
ko.bindingHandlers.popover = { 
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
     var $element = $(element); 
     // read popover options 
     var popoverBindingValues = ko.utils.unwrapObservable(valueAccessor()); 

     // set popover title 
     var popoverTitle = popoverBindingValues.title; 

     // 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/>', { 
      "class" : "ko-popover", 
      "id" : domId 
     }).html(tmplHtml); 

     // set content options 
     options = { 
      content: tmplDom[0].outerHTML, 
      title: popoverTitle 
     }; 

     // Need to copy this, otherwise all the popups end up with the value of the last item 
     var popoverOptions = $.extend({}, ko.bindingHandlers.popover.options, options); 

     // bind popover to element click 
     $element.bind(trigger, function (e) { 
      $(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]); 
      } 
     }); 

     // Also tell KO *not* to bind the descendants itself, otherwise they will be bound twice 
     return { controlsDescendantBindings: true }; 
    }, 
    options: { 
     placement: "right", 
     title: "", 
     html: true, 
     content: "", 
     trigger: "manual", 
     container: 'body' 
    } 
}; 

var ItemModel = function (data) { 
    var self = this; 
    self.label = ko.observable(data.label); 
    self.required = ko.observable(data.required); 
    self.options = ko.observableArray(ko.utils.arrayMap(data.options, function(option) { 
     return option; 
    })); 
} 

var ViewModel = function() { 
    var self = this; 
    self.initItems = [ 
     {"label":"Item 1", "required": false, "options": [1,2,3,4,5,6]}, 
     {"label":"Item 2", "required": true, "options": [1,2,3]}, 
     {"label":"Item 3", "required": false, "options": []}, 
     {"label":"Item 4", "required": true, "options": [1,2,3,6]} 
    ]; 

    self.items = ko.observableArray(ko.utils.arrayMap(self.initItems, function (item) { 
     return new ItemModel(item); 
    })); 
}; 

$(function(){ 
    ko.applyBindings(new ViewModel); 
}); 

http://billpull.github.com/knockout-bootstrap/

ответ

0

DEMO

Может быть, вы можете использовать ko.applyBindingsToNode() для этого. Сначала визуализируйте шаблон, затем привяжите popover.

$element.bind(trigger, function (e) { 

    ko.applyBindingsToNode(tmplDom[0], {template : { name :'settingsPopover', data : viewModel}});    
    options = { 
     content: tmplDom[0].outerHTML, 
     title: popoverTitle 
    }; 

    // Need to copy this, otherwise all the popups end up with the value of the last item 
    var popoverOptions = $.extend({}, ko.bindingHandlers.popover.options, options);    
    $(this).popover(popoverOptions).popover('show');   
    // } 
}); 
0

Когда Вы связываете нажмите на элемент в вашем обязательном пироге, Вы инициализация начальной загрузки поповера и затем appply привязки к потомкам. Вот почему bootstrap popover неправильно вычисляет его положение (нет вложенных li-s, но их высота равна нулю). После этого нокаут добавляет элементы li-s и изменения высоты пополнения, и вам нужно пересчитать положение popover.

После следующего щелчка Вы повторно инициализируете bootstrap popover, но не применяете привязки, в этом случае позиция popover вычисляется правильно.

+0

Вы можете думать о любом случае, чтобы обойти это, поскольку я не знаю, могу ли я применить привязки перед созданием popover. – BillPull

+0

К сожалению, bootstrap и knockout немного несовместимы. В настоящее время bootstrap заменяет содержимое popover кодом html на открытом, это место, где теряются привязки нокаута. Также открытый метод содержит вычисления позиции, поэтому вы не можете пересчитывать его отдельно после применения popover.open и привязки нокаута. Поэтому я бы предложил переписать bootstrap popover - либо разрезать вычисления позиции для отдельного метода и запускать его после применения привязки нокаута или ... – Kasheftin

+0

... изменить логику popover, чтобы открытые и скрытые методы изменяли только видимость содержимого popover, не влияя на структуру dom – Kasheftin

0
$element.bind(trigger, function (e) { 

ko.applyBindingsToNode(tmplDom[0], {template : { name :'settingsPopover', data : viewModel}});    
options = { 
    content: tmplDom[0].outerHTML, 
    title: popoverTitle 
}; 

// Need to copy this, otherwise all the popups end up with the value of the last item 
var popoverOptions = $.extend({}, ko.bindingHandlers.popover.options, options);    
$(this).popover(popoverOptions).popover('show');   
// } 
}); 

поповер никогда не закрывается по какой-то причине !! :(

Смежные вопросы