Zulko / eagle.js

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

Trigger reload of slide container when adding slides dynamically #47

Closed raLaaaa closed 6 years ago

raLaaaa commented 6 years ago

Hey there,

I've currently implemented a basic slideshow with various different slides. My slides are stored in an array called active slides and are iterated as shown in the following example:

slide(v-for="(slide, index) in activeSlides"...

Everything works fine and slides are rendered successfully. How ever I want do add new slides dynamically to my presentation so I decided to add them to my activeSlide array. Unfortunately eagle.js does not show the newly added slides. I'm adding the slides in my mounted method as following:

mounted() {
        setInterval(() => {
            this.nextStep();
        }, 5000);

        Vue.http
            .get('/allSlides')
            .then(
                (response) => {
                    this.fillActiveArray(response.body);
                },
                (error) => {
                    console.log(error);
                },
            );

I'm successfully retrieving the slides from the server but my array is not update and the slides are not rendered successfully. Documentation says:

The only times you need to refresh the page is when you add remove or add slides to the presentation.

How can I trigger this refresh? Or are you referring to an entire site refresh? If I refresh my entire site it wont have any effects though because my activeSlide array will be re initialized and I'll receive the same state as before. Any hints on how this is supposed to work would be highly appreciated! :)

Zulko commented 6 years ago

Vue doesnt react to arrays/objects the same way as other variables. See the top of this page:

https://vuejs.org/2016/02/06/common-gotchas/

raLaaaa commented 6 years ago

Shouldnt this work then?

fillActiveArray(slides) {
            for(var i = 0; i < slides.length; i++){
            this.$set(this.activeSlides, i, slides[i]);
            }
        }

Thanks for the quick reply and your hint!

Zulko commented 6 years ago

It should. One way that always works it to completely assign a new array:

var newActiveSlides = []
// ... fill the array
this.activeSlides = newActiveSlides;
raLaaaa commented 6 years ago

I think I identified the true problem:

    slide(v-for="(slide, index) in activeSlides").local-eg-theme-mytheme(enter='fadeIn'  leave='fadeOut')
      eg-transition(enter='zoomIn')
       div(class='rectangle')
         p(class='head') HeadTeast
           div
             ul
               <p>Test</p>

this does not work, how ever this does:

   slide.local-eg-theme-hamburg(enter='fadeIn'  leave='fadeOut')
      eg-transition(enter='zoomIn')
       div(class='rectangle')
         p(class='head') Geburtstage
           div
             ul
               <p v-for="(slide, index) in activeSlides">Test</p>

Is slide not working with v-for?

yaodingyd commented 6 years ago

You need to update slides after you reset your slide component

var newActiveSlides = []
// ... fill the array
this.activeSlides = newActiveSlides;

this.$nextTick(() => {
 this.slides = []
 this.findSlides()
})

Also pay attention if your new activeSlides is smaller than before, you might need to manually set currentSlideIndex too.

Zulko commented 6 years ago

@raLaaaa if you use v-for you elements should have a :key=, it is very important for reactivity.

raLaaaa commented 6 years ago

@yaodingyd I think this did it for me, thanks for clarification! @Zulko as I'm relatively new to vue I'm not really sure about this, I'll read about it and keep your hint in mind.

Thank you two :) !

Zulko commented 6 years ago

Cool ! But I really hope this can also be solved without $nextTick. I've done a few projects with Vue and I always find a way to avoid "$nextTick".

yaodingyd commented 6 years ago

@Zulko I don't find a good solution bypass $nextTick. findSlides() checks slideshow's $children and its reactivity takes time. Without $nextTick, findSlides() would still uses the old $children to set slides.

Unrelated, do you think we need to wrap mounted method inside a function (maybe called init) and user could re-init without refresh?

sleroy commented 5 years ago

I have the same issue and I would appreciate a working example.

yaodingyd commented 5 years ago

@sleroy you can see discussion here https://github.com/Zulko/eagle.js/issues/70

sleroy commented 5 years ago

Thank you, I have done the following thing :

 setTimeout(() => {
                this.slides = [];
                this.findSlides();
                this.currentSlide = this.slides[0];

                console.log("Slides have been refreshed", this.slides.length); 
            }, 1);

However the dummy / backup slide is never removed.

yaodingyd commented 5 years ago

@sleroy your code would not work since you set slides to be empty.