Search code examples
vue.jscarouselaccordionvue-clibootstrap-vue

Is there a way, to "emit" a built in event, by hard coding it in Vue instance?


I would like to link two components with each other in my Vue project. I use two-way binding for that, so I have a parent, and two child components.

The concept:

We see a carousel in the left side of the screen, and we see an accordion in the right side. I built the carousel and the accordions with v-for from a database file.

When I click in some of the accordion it drops down, and I need a reaction from a carousel component, to slide exactly there, where I clicked in the accordion.

Like:

carousel: banana, apple, house

accordion: banana, apple house

So when im clicking in the apple accordion button, I need the slider to go to the where are the apple is displayed, and reverse.

As I said, I already bind the two components to each other, so when I'm clicking one of the accordion buttons like @click="onShowStart(index)", I get that index in the another child too, and it's changing dynamically vica-versa by sliding or clicking. So the indexes are already linked and its dynamic.

My problem is I don't know how to trigger an event, like @sliding-start from vue instance in the watch field. So I watch the "actualPosition" prop in my component, and when its changed (from 3 to 1 for example), I would like to start a sliding event to the new value of the actualPosition.

So i need something like:

 this.$emit('sliding-start', actualPosition);

I've been sitting at this problem for days, but I think my whole thinking is wrong. But before i believe this, im asking you first.

Here is my code for the Parent component:

        <div class="row">
            <carousel :actualPosition="actualPosition" class="col bg-dark" @sendTheCarouselPosition="updateAccordion($event)"></carousel>
            <accordion :actualPosition="actualPosition" class="col bg-dark" @sendTheAccordionlPosition="updateCarousel($event)"></accordion>
        </div>

<script>
    export default {

        data() {
            return {
                actualPosition: null,
            }
        },

        methods:{
            updateAccordion: function (updatedAccordion){
                this.actualPosition = updatedAccordion;
            },
            updateCarousel: function(updatedSlider){
                this.actualPosition = updatedSlider
            }
        },
    }
</script>

My Accordion component:

<template>
    <div role="tablist">
        <b-card no-body class="mb-1" v-for="(item, index) in dataForProject">
            <b-card-header header-tag="header" class="p-1" role="tab">
                <b-button block href="#" v-b-toggle="'accordion-' + index" variant="info" @click="onShowStart(index)" >{{ item.title }}</b-button>
            </b-card-header>
            <b-collapse :id="'accordion-' + index" visible accordion="my-accordion" role="tabpanel">
                <b-card-body>

                    <div>
                        <h1>data from Carousel sibling: {{ actualPosition }}</h1>
                    </div>

                    <b-card-text>{{ item.content }}</b-card-text>
                </b-card-body>
            </b-collapse>
        </b-card>
    </div>
</template>


<script>
    import myDataBase from '../data2'

    export default {

        props:['actualPosition'],

        watch:{
            actualPosition: function () {


            },
        },

        data() {
            return {
                dataForProject: myDataBase,
            }
        },

        methods:{
            onShowStart: function (accordionIndex) {
                this.$emit('sendTheAccordionlPosition', accordionIndex);

            },



        },
    }
</script>

And my Carousel component:

<template>
    <div>
        <p class="mt-4 text-white">
            data from Accordion sibling: {{ actualPosition }}
        </p>
        <b-carousel
                id="carousel-1"
                :interval="0"
                controls
                indicators
                background="#ababab"
                img-width="1024"
                img-height="480"
                style="text-shadow: 1px 1px 2px #333;"
                ref="slider"
                @sliding-start="onSlideStart"
                @sliding-end="onSlideEnd"
        >

            <b-carousel-slide v-for="(item, index) in dataForProject" :id="index" >
                <img
                        slot="img"
                        class="d-block img-fluid w-100"
                        width="1024"
                        height="480"
                        :src="item.image_url"
                        alt="image slot"
                >
            </b-carousel-slide>
        </b-carousel>
    </div>
</template>

<script>
    import myDataBase from '../data2'

    export default {
        props:['actualPosition'],

        watch: {
            actualPosition: function () {

            },
        },


        data() {
            return {
                //slide: 0,
                dataForProject: myDataBase,
            }
        },
        methods: {
            onSlideStart(slide) {
                this.$emit('sendTheCarouselPosition', slide);
            },
            onSlideEnd(slide) {

            },

        }
    }
</script>

Solution

  • Okay, so my whole concept was wrong, and i was wrong about this.

    I should have used the v-model for this whole thing. And nothing more.

    I added the v-model to the target tags, and my problem is solved.