Zulko / eagle.js

A hackable slideshow framework built with Vue.js
https://zulko.github.io/eaglejs-demo/
ISC License
4.08k stars 223 forks source link

Adding slides dynamically with v-for #70

Closed moteey closed 5 years ago

moteey commented 5 years ago

I have a case where I need to display slides from an array with v-for.

If I have the array in component's data function, everything works fine (seems like slides are initialized when the slideshow is mounted).

However, if my array is empty when the slideshow is mounted, and later changed (via Vuex), then I get the following error:

[Vue warn]: Error in mounted hook: "TypeError: Cannot set property 'step' of undefined"

Is it possible to render slides with v-for if the data is not yet available when component is mounted?

yaodingyd commented 5 years ago

Two step:

  1. your array has to have at least 1 slide for now. It can be empty slide like <slide/>, but there must be at least 1 slide for slideshow to initialize properly.
  2. After your state changed You can call 'findSlides()' to reinitialize
moteey commented 5 years ago

Thanks, that was very helpful!

moteey commented 5 years ago

One more question though. What is the best way to remove the first (empty) slide when the state changes? Looking at the findSlides() method it seems to push new slides onto the existing array, without resetting it first...

yaodingyd commented 5 years ago

Can you do it in your state setting? something like initial state is one dummy slide, then vuex will mutate state to your real slides?

moteey commented 5 years ago

I'm doing something similar, yes.

Problem is that this.slides ends up with one item too many after calling this.findSlides() for the second time. Probably because that method adds onto this.slides, so the "dummy" slide is never removed from there.

That results in one extra step in the beginning, so I have to press "Next" to go to the first slide.

Pasting a simplified example below (change of the state in afterMounted method, to hide Vuex complexity):

Template:

<slide v-for="mySlide in mySlides">
  {{mySlide}}
</slide>

Script:

data () {
  return {
    mySlides: ['dummy']
  }
},
methods: {
  afterMounted () {
    this.mySlides = ['real1', 'real2', 'real3']

    setTimeout(() => {
      this.findSlides()

      console.log(this.slides.length) // returns 4 instead of 3
    }, 10)
  }
}
yaodingyd commented 5 years ago

That's a valid point. Sometime ago I was thinking that should be a method initSlides that init from a clean state. Right now I thinking that findSlides should reset slide to empty array.

yaodingyd commented 5 years ago

Actually, you can manually set this.slides be to empty before this.findSlides

moteey commented 5 years ago

Yeah, was still running into issues when I did that - having an empty slide at the beginning.

Turns out that this.currentSlide was still holding a reference to the old slide, so I did this: this.currentSlide = this.slides[0] (after calling this.findSlides()).

This seems to solve it for now 👍

initSlides could be useful indeed, since it would probably to all this manual work behind the scenes.

yaodingyd commented 5 years ago

If you want to do it, a PR is welcome

killua99 commented 5 years ago

@moteey could I see a code snipe of that implementation? Thanks

yaodingyd commented 5 years ago

findSlides would do initialization correctly in v0.4.2