如何在DOM更新后调用Knockout bindingHandler->更新

时间:2013-08-07 01:23:32

标签: ajax jquery-ui knockout.js bindinghandlers

我在KO bindingHandler中使用jquery手风琴,我必须填充手风琴UI使用的DOM,按照app要求使用ajax。

this.faqList = ko.observableArray();
$.ajax({
  url: 'getFaqs'
}).done(function( data ) {
  that.faqList(data);
});

我的bindingHandler应该像

一样简单
ko.bindingHandlers.koAccordion = {
  init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
    $(element).accordion(valueAccessor());

  },
  update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
      $(element).accordion(valueAccessor());
  }
};

当observableArray(faqList)发生变化时会调用update方法,但此时UI手风琴需要已经填充的DOM结构,这是不正确的,看起来KO在调用update方法后创建。 在使用新内容填充DOM结构后,如何实现调用更新?

这是默认的DOM。

<ul class="question-list" data-bind="koAccordion: {
          active: false,
          autoHeight: false, 
          collapsible: true}">
  <!-- ko foreach: faqList -->
    <li>
      <div class="header">
        <span class="rigth-arrow"></span>
        <a href="#" data-bind="text: title"></a>
      </div>
      <div class="content">
        <h2 data-bind="text: title"></h2>
        <div data-bind="text: content"></div>
      </div>
    </li>
  <!-- /ko -->
  </ul>

CodePen

2 个答案:

答案 0 :(得分:3)

koAccordion.update没用,因为你永远不会更新那个绑定值:它在标记中是静态的,并且不包含任何可观察对象。 foreach绑定为您的目的提供afterRender回调:

var vm = function() {
    // ...
    this.initAccordion = function(element) {
        $(element).accordion(accordionOptions);
    };
};


<!-- ko foreach: { data: faqList, afterRender: initAccordion } -->

但是,在这种情况下,您必须将accordion选项移出绑定值。如果你坚持使用自定义绑定,一种方法是将工作委托给foreach绑定,在途中将afterRender插入绑定值:

ko.bindingHandlers.koAccordion = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel,
                   bindingContext) {
        var newValue = ko.computed(function() {
            var value = ko.unwrap(valueAccessor());
            value.afterRender = function(element) {
                $(element).accordion(value);
            };
            return value;
        });
        return ko.bindingHandlers.foreach.init(element, newValue,
            allBindingsAccessor, viewModel, bindingContext);
    },
    update: function(element, valueAccessor, allBindingsAccessor, viewModel,
                     bindingContext) {
        return ko.bindingHandlers.foreach.update(element, valueAccessor,
            allBindingsAccessor, viewModel, bindingContext);
    }
};

像这样使用它:

<ul class="question-list" data-bind="koAccordion: {
      data: faqList,
      active: false,
      autoHeight: false, 
      collapsible: true }">
   <li>...bindings...</li>
</ul>

请参阅我在帖子中分享的演示页面:http://codepen.io/anon/pen/IJpuj

答案 1 :(得分:1)

This is my final code
ko.bindingHandlers.koAccordion = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
  var newValue = ko.computed(function() {
    var value = ko.unwrap(valueAccessor());
    value.afterRender = function(renderedElement, loopEntryObject) {
      if ( loopEntryObject == value.data()[value.data().length - 1] ) {
        if ($(element).data('accordion')) {
          $(element).accordion('destroy');
        }
        $(element).accordion(value);
      }
    };
    return value;
  });
  return ko.bindingHandlers.foreach.init(element, newValue, allBindingsAccessor, viewModel, bindingContext);
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
  return ko.bindingHandlers.foreach.update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
}