Search code examples
owl-carouselractivejs

How to reinit decorator with new RactiveJS data


Here I am again with quite an interesting question. Say, for example, I have the following:

<div decorator="carousel">
   {{ # filteredUsers }} // computed value from users array and a filter input
      <div class="item">{{ name }}</div>
   {{ / }}
</div>

Using owlCarousel 2 as a decorator like the following:

decorators: {
    carousel: function( node )
    {

        var owl = $( node );
        owl.owlCarousel({
            items: 1,
            loop: $( node ).children().length > 1 ? true : false,
            autoplay: true,
            autoplayTimeout: 3000,
            autoplaySpeed: 500,
            dots: false
        });

        return {
            update: function( )
            {
                owl.data('owlCarousel').destroy();
                owl.removeClass('owl-carousel owl-loaded');
                owl.find('.owl-stage-outer').children().unwrap();

                // carousel destroyed
                // reinit carousel

            },
            teardown: function () {
                owl.data('owlCarousel').destroy();
                owl.trigger('destroy.owl.carousel').removeClass('owl-carousel owl-loaded');
                owl.find('.owl-stage-outer').children().unwrap();
            }
        }
    }
}

Problem at reinitiating the carousel is that when I do this:

owl.find('.owl-stage-outer').children().unwrap();

I basically get all the results that were in the slider at the begining and not the newly computed ones with the filter applied ( even though the computed array is correct ) ractive is not in control of the elements that are there anymore.

I don't know if I explained this... correctly, hopefully you guys will understand the problem here.

The idea is that I have applied a filter, which gets computed correctly, but the html result that comes out after unwrapping the children is not in Ractive's... custody. It does not belong to Ractive, it's just ... html.

So I'm thinking that, I don't have to unwrap the children as it doesn't do anything, just call the destroy method, remove the classes like this:

owl.data('owlCarousel').destroy();
owl.removeClass('owl-carousel owl-loaded');

And this is the part I can't figure out.. how is it possible for me to like... reinitialize the template, or, that part of template, or, reinitialize the decorator itself so it belongs to ractive again.

Hopefully I got you to understand what's the problem. Main point, how do I correctly implement a filter to a owlCarousel decorator, how to teardown and re-render.


Solution

  • Probably what happens is when you initialize your owl-carousel, the plugin replaces your div.item's with its own HTML nodes (or hides the original nodes and appends new ones). That's why it may look like Ractive doesn't have control over carousel any more. What you can do is perhaps write a decorater at the owl item level. Then, for this item decorator you can use owl's events API to add or remove items dynamically. I am seeing for instance add.owl.carousel and remove.owl.carousel which may come handy for dynamic manipulation of items.

    You can first try to do this without Ractive: add a button that will insert a new item and another one to delete one. Once you have the machanics going (making owl happy) you can adapt this to a Ractive decorator.

    Another solution may be moving your <div decorator="carousel"> inside Ractive's {{ # filteredUsers }} loop (i.e. print it only before the first item and the closing tag after the last item). That way, when filteredUsers changes the whole carousel node with its children will be rerendered by Ractive and your code may start working with some additional changes.