vue-flickity icon indicating copy to clipboard operation
vue-flickity copied to clipboard

Not working on first render when using custom components with v-for

Open freshlySqueezedBananas opened this issue 6 years ago • 11 comments

Hi,

Similarly with @angelorc's issue when using a custom component with v-for, the slides are rendered outside flickity's viewport. Tried the solution @exxy provided to no avail.

This doesn't work

<flickity v-if="Object.keys(components).length > 0" ref="flickity" :options="flickityOptions">
      <picker-slide v-for="(item, index) in components" :key="index"
                            :name="index"
                            :item="item"/>
  </flickity>

This works

<flickity v-if="Object.keys(components).length > 0" ref="flickity" :options="flickityOptions">
      <div class="carousel-cell" v-for="(item, index) in components" :key="index"
                            :name="index"
                            :item="item">
        {{ item.name }}
      </div>
  </flickity>

The weird thing is, it only won't work on first render. If I return back to the page where the flickity slider is, it's rendered nicely. Same behaviour when using custom components inside the div on the 2nd method. On first render they will render weirdly, and when I return to that page. it's all rendered as intended.

freshlySqueezedBananas avatar Apr 09 '18 13:04 freshlySqueezedBananas

@freshlySqueezedBananas could you provide me with a codepen example?

drewjbartlett avatar Apr 13 '18 14:04 drewjbartlett

Same problem for me. Just don't have the time for a codepen sorry.

But I used:

<flickity ref="flickity" :options="flickityOptions" v-if="windowWidth < 768">

				<destinations-list 
					v-for="(list, index) in lists" 
					:key="index" 
					:list="list"
					:class="'blog-container'"></destinations-list>
			</flickity>

With destinations-list.vue

 <template>
<div class="p-2">
	<a 
	:href="/test">
		<div class="blog-card box-shadow-none rounded-0" :class="location">
	
			<div class="title-content">
			    <h5 class="osans text-uppercase">{{ list[0] }}</h5>
			    <hr />
		    	<div class="intro bfont"><em>{{ list[1] }}</em></div>
		  	</div>

			<div class="card-info bfont">
				<div>
				{{ list[2] }}
				</div> 
			</div>

			<div class="gradient-overlay"></div>
			<div class="color-overlay"></div>
		</div>
	</a>
</div>
</template>

It doesn't work. The divs are not inside of the slider...

pmochine avatar Apr 15 '18 19:04 pmochine

hmmm maybe a scoped slot could solve this? Now that I know the issue I can attempt to fix :D Thanks!

drewjbartlett avatar Apr 15 '18 21:04 drewjbartlett

I've been looking into this issue - can't seem to find a fix. Any updates?

UPDATE:

It seems that setting lazy-load to true and using the "data-flickity-lazyload" as the default src option fixes this problem.

josh9060 avatar May 04 '18 16:05 josh9060

As a fix I'd suggest wrapping the new Flickity call inside the init method in a this.$nextTick. Happy to make a PR if needed.

edtownend avatar Aug 01 '18 08:08 edtownend

Experiencing same issue here.

@edtownend what do you mean by "flickity call", can you please elaborate?

In the parent component I've tried doing:

mounted() {
    this.$nextTick(function() {
        this.$refs.flickity.rerender()
    })
}

But that doesn't always work. Wrapping rerender call in a timeout of like 100ms seems to be fixing it for me but that's a very hacky solution

Rrrafau avatar Aug 01 '18 14:08 Rrrafau

I think the reason that's not working for you is that at the time the parent component is mounted, the child vue-flickity component won't be mounted yet. Instead I think it should be in the init() method on the actual component, eg.

init() {
      this.$nextTick(() => {
          this.$flickity = new Flickity(this.$el, this.options);
          this.$emit('init', this.$flickity);
    });
},

I'm not actually using this component as I'd already written my own that does exactly the same thing, but that's working for me.

edtownend avatar Aug 02 '18 10:08 edtownend

Heres a quick workaround for future visitors; for the first render don't load your component until the array is populated and upon updating the array re-render the whole component via a v-if flag that's being toggled in the server call. Additionally wrapping vue's transition component around your component will actually make it behave sort of normal.

fatihgune avatar Nov 09 '18 22:11 fatihgune

Im having this problem too, I have my cells with a v-for and they load correctly, but the slider doesn't work until I change pages, the first load is just cells in top of other cells. Im triyng with v-if for the container, but I got the same result. Any ideas?

davidjmz avatar Apr 07 '20 16:04 davidjmz

Has anyone got a solution for this?

EDIT: Found this https://github.com/drewjbartlett/vue-flickity/issues/2#issuecomment-352671946

And it works, although using slides.length is fine (if your data is an array), not sure why the comment uses Object.keys.

roberttolton avatar Dec 01 '21 14:12 roberttolton

			<destinations-list 
				v-for="(list, index) in lists" 
				:key="index" 
				:list="list"
				:class="'blog-container'"></destinations-list>
		</flickity>

alnazer avatar Dec 13 '22 18:12 alnazer