Owl Carousel 2 beta 3 and knockout 3.3

I am trying to create a dynamic carousel with data coming from an observable knockout array.

There are several problems with the result.

  • The carousel is not displayed at all, instead all the owl elements have an active class and are displayed on the page.

  • Another problem is that none of the dots or buttons are displayed.

What I'm trying to do is add or remove items to myItems collection and automatically update the carousel in the user interface

I am using knockout 3.3, base zurb 5, jQuery 2.1.4

custom knockout handler

(function (factory) {
  if (typeof define === "function" && define.amd) {
    define(["knockout", "jquery", "jquery.ui.sortable"], factory);
  } else {
    factory(window.ko, jQuery);
  }
})(function (ko, $, undefined) {
  /**
   * Helper function that refreshes the items of the given owl instance.
   *
   * @param {{ $owlWrapper: jQuery, $owlItems: jQuery, $userItems: jQuery, itemsAmount: number }} owl
   *          The owl carousel instance that should be refreshed
   */
  var refreshOwl = function (owl) {
    // find all owl items that are currently wrapped in the owl wrapper element
    owl.$owlItems = owl.$stage.children(".owl-item");

    // extract the elements that are wrapped in the owl items
    owl.$userItems = owl.$owlItems.children();
    owl.itemsAmount = owl.$userItems.length;

    // TODO: check if items have been removed and adjust owl internal current position
    owl.refresh();

  };

  /**
   * Helper function for creating an options object that can be passed to ko.bindingHandlers.template.init as a value for
   * the 'valueAccessor' parameter.
   *
   * @param {{data: *, as: string, afterRender: function, afterAdd: function, beforeRemove: function}} options
   * @param {function} afterRender
   * @returns {{foreach: *, as: string, afterRender: function, afterAdd: function, beforeRemove: function}}
   */
  var makeTemplateBindingOptions = function (options, afterRender) {
    var templateOptions = {
      foreach: options.data,
      as: options.as,
      afterRender: afterRender,
      afterAdd: options.afterAdd,
      beforeRemove: options.beforeRemove
    };

    if (options.afterRender) {
      var userAfterRender = options.afterRender;

      templateOptions.afterRender = function (element, data) {
        if (afterRender) {
          afterRender.call(data, element, data);
        }

        userAfterRender(data, element, data);
      };
    }

    return templateOptions;
  };

  ko.bindingHandlers.owlCarousel = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
      // the options that have been configured with the owlCarousel binding
      var options = ko.utils.unwrapObservable(valueAccessor());

      // the bound element as a jQuery object
      var $elem = $(element);

      // initialize owl carousel
      var owlOptions = options.owlOptions || {};
      $elem.owlCarousel(owlOptions);

      // the owl instance that has just been created
      var owl = $elem.data("owl.carousel"); // $elem.data("owlCarousel");

      // register a callback that is being executed when the element is removed
      // in that case the carousel is no longer required and can be destroyed
      ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
        if (owl) {
          owl.destroy();
        }
      });

      // create options for the template binding with a afterRender event hook
      // that causes the carousel to refresh its internal state
      var templateOptions = makeTemplateBindingOptions(options, function () {
        refreshOwl(owl);
      });

      return ko.bindingHandlers.template.init(owl.$stage[0], function () { return templateOptions; }, allBindingsAccessor, viewModel, bindingContext);
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
      // the options that have been configured with the owlCarousel binding
      var options = ko.utils.unwrapObservable(valueAccessor());

      // the bound element as a jQuery object
      var $elem = $(element);

      // the owl instance that has been associated with the element
      var owl = $elem.data("owl.carousel");

      // create options for the template binding with a afterRender event hook
      // that causes the carousel to refresh its internal state
      var templateOptions = makeTemplateBindingOptions(options, function (element, data) {
        refreshOwl(owl);
      });

      ko.bindingHandlers.template.update(owl.$stage[0], function () { return templateOptions; }, allBindingsAccessor, viewModel, bindingContext);
    }
  };
});

Javascript code for binding to view

  var myItems = ko.observableArray([
    { name: 'Image 1', url: "http://placehold.it/150x200&text=book cover1" },
    { name: 'Image 2', url: "http://placehold.it/150x200&text=book cover2" },
    { name: 'Image 3', url: "http://placehold.it/150x200&text=book cover3" },
    { name: 'Image 4', url: "http://placehold.it/150x200&text=book cover4" },
    { name: 'Image 5', url: "http://placehold.it/150x200&text=book cover5" },
    { name: 'Image 6', url: "http://placehold.it/150x200&text=book cover6" },
    { name: 'Image 7', url: "http://placehold.it/150x200&text=book cover7" },
    { name: 'Image 8', url: "http://placehold.it/150x200&text=book cover8" }
  ]);

HTML:

      <div id="myCarousel"
           class="owl-carousel owl-theme book-slide large-11 large-centered columns"
           data-bind="owlCarousel: { data: myItems, owlOptions: { items: 3 } }">

        <img data-bind="attr: { src: url, title: name, alt: name }" />

      </div>

HTML output:

      <div class="owl-carousel owl-theme book-slide large-11 large-centered columns owl-loaded owl-drag" id="myCarousel" data-bind="owlCarousel: { data: myItems, owlOptions: { responsive:{ 0:{ items:2}, 600:{items:3}, 1000:{items:5}} } }">
<div class="owl-stage-outer">
  <div class="owl-stage" style="transition:all; width: 1016px; transform: translate3d(0px, 0px, 0px);">
    <div class="owl-item active" style="width: 203.2px;">
      <img title="Image 1" alt="Image 1" src="http://placehold.it/150x200&amp;text=book cover1" data-bind="attr: { src: url, title: name, alt: name }">
    </div>
    <div class="owl-item active" style="width: 203.2px;">
      <img title="Image 2" alt="Image 2" src="http://placehold.it/150x200&amp;text=book cover2" data-bind="attr: { src: url, title: name, alt: name }">
    </div>
    <div class="owl-item active" style="width: 203.2px;">
      <img title="Image 3" alt="Image 3" src="http://placehold.it/150x200&amp;text=book cover3" data-bind="attr: { src: url, title: name, alt: name }">
    </div>
    <div class="owl-item active" style="width: 203.2px;">
      <img title="Image 4" alt="Image 4" src="http://placehold.it/150x200&amp;text=book cover4" data-bind="attr: { src: url, title: name, alt: name }">
    </div>
    <div class="owl-item active" style="width: 203.2px;">
      <img title="Image 5" alt="Image 5" src="http://placehold.it/150x200&amp;text=book cover5" data-bind="attr: { src: url, title: name, alt: name }">
    </div>
    <div class="owl-item active" style="width: 203.2px;">
      <img title="Image 6" alt="Image 6" src="http://placehold.it/150x200&amp;text=book cover6" data-bind="attr: { src: url, title: name, alt: name }">
    </div>
    <div class="owl-item active" style="width: 203.2px;">
      <img title="Image 7" alt="Image 7" src="http://placehold.it/150x200&amp;text=book cover7" data-bind="attr: { src: url, title: name, alt: name }">
    </div>
    <div class="owl-item active" style="width: 203.2px;">
      <img title="Image 8" alt="Image 8" src="http://placehold.it/150x200&amp;text=book cover8" data-bind="attr: { src: url, title: name, alt: name }">
    </div>
  </div>
</div>
<div class="owl-nav disabled">
  <div class="owl-prev">prev</div>
  <div class="owl-next">next</div>
</div>
<div class="owl-dots disabled">
  <div class="owl-dot active">
    <span></span>
  </div>
</div>

Any ideas on what I'm doing wrong?

+4
source share

All Articles