How do I use Slick.io carousel with meteor and collections?

533 views Asked by At

I've come across kenwheeler's image carousel and I'm trying to make it work within my Meteor app. I'm using the risul:slick wrapper.

The problem is that the recommendation is to initialise the template on rendering but at that point the images in the subscription haven't necessarily all been loaded... if I use static images on a local drive everything works well, but if I try and create slides within an {{#each}} loop it all goes wrong.

I have tried using a {{#if Template.subscriptionsReady}} block and manually call the initialiser using a Template helper but that hasn't worked either.

The interesting thing I noticed when putting a console.log statement into the initialiser is that it seems to get called three times when I first navigate to the page but when I do a browser refresh it only gets called once and breaks (this happens with static images as well if I don't have the initialisation code within the onRender block?).


Template code with static references (working as long as the .slick() call is sitting within the Template.image.onRendered block):

<template name="image">
  <div id="carousel">
    <div id="demo-box"><img src="../../img/brush.jpg" /></div>
    <div id="demo-box"><img src="../../img/drill.jpg" /></div>
    <div id="demo-box"><img src="../../img/hammer.jpg" /></div>
    <div id="demo-box"><img src="../../img/shovel.jpg" /></div>
    <div id="demo-box"><img src="../../img/spanner.jpg" /></div>
    <div id="demo-box"><img src="../../img/tape.jpg" /></div>
  </div>
</template>

Reactive template

<template name="image2">
  {{#if Template.subscriptionsReady}}
    {{slickInit}}
    <div id="carousel">
      {{#each images}}
        <div id="demo-box"><img src="{{url}}" /></div>
      {{/each}}
    </div>
  {{else}}
    <div>Loading...</div>
  {{/if}}
</template>

Template.image.onCreated( () => {
  // limit of images returned = 5
  Template.instance().subscribe('images', 5);
});

Template.image.onRendered( () => {
  $('#carousel').slick({
    infinite: false,
    dots: true,
    slidesToShow: 1,
    slidesToScroll: 1,
    arrows: true
  });
});

Template.image.helpers({
  images() {
    return Images.find();
  },

  // this is supposed to replace the onRender call
  slickInit() {
    $('#carousel').slick({
      infinite: false,
      dots: true,
      slidesToShow: 1,
      slidesToScroll: 1,
      arrows: true
    });
  }
});
1

There are 1 answers

1
Achtel On BEST ANSWER

It works if each item of the carousel is handled within its own template which can then intialise slick onRendered.

<template name="image">
  {{#if Template.subscriptionsReady}}
    <div id="carousel">
      {{#each images}}
        {{> imageItem}}
      {{/each}}
    </div>
    <button type="button" class="btn btn-default" id="addSlide">Add</button>
  {{else}}
    <div>Loading...</div>
  {{/if}}
</template>

<template name="imageItem">
  <div id="demo-box"><img src="{{url}}" /></div>
</template>

Template.imageItem.onRendered( () => {
  $('#carousel').slick({
    infinite: false,
    dots: true,
    slidesToShow: 1,
    slidesToScroll: 1,
    arrows: true
  });
});