Event from parent to child component

10,250

Solution 1

Just have a variable (call it moreLoaded) that you increment each time loadMore is called. Pass that and currentPosition to your search component as props. In Search, you can watch moreLoaded and take action accordingly.

Update
Hacky? My solution? Well, I never! ;)

You could also use a localized event bus. Set it up something like this:

export default {
    components: {
        Search
    },
    data() {
        return {
            bus: new Vue(),
            transactions: [], 
            currentPosition: 0 
        }
    },
    methods: {
        loadMore() {
            this.bus.$emit('loadMore', {
                currentPosition: this.currentPosition
            });
        }
    }
}

and pass it to Search:

<search :bus="bus"></search>

which would take bus as a prop (of course), and have a section like

created() {
    this.bus.$on('loadMore', (args) => {
        // do something with args.currentPosition
    });
}

Solution 2

I think that @tobiasBora's comment on @Roy J's answer is pretty important. If your component gets created and destroyed multiple times (like when using v-if) you will end with your handler being called multiple times. Also the handler will be called even if the component is destroyed (which can turn out to be really bad).

As @tobiasBora explains you have to use Vue's $off() function. This ended up being non trivial for me beacuse it needed a reference to the event handler function. What I ended up doing was define this handler as part of the component data. Notice that this must be an arrow function, otherwise you would need .bind(this) after your function definition.

export default {
    data() {
        return {
            eventHandler: (eventArgs) => {
                this.doSomething();
            }
        }
    },
    methods: {
        doSomething() {
            // Actually do something
        }
    },
    created() {
        this.bus.$on("eventName", this.eventHandler);
    },
    beforeDestroy() {
        this.bus.$off("eventName", this.eventHandler);
    },
}
Share:
10,250

Related videos on Youtube

madeye
Author by

madeye

Just an average programmer.

Updated on June 04, 2022

Comments

  • madeye
    madeye over 1 year

    I have event that is generated in parent component and child has to react to it. I know that this is not recommended approach in vuejs2 and i have to do a $root emit which is pretty bad. So my code is this.

    <template>
        <search></search>
        <table class="table table-condensed table-hover table-striped" v-infinite-scroll="loadMore" infinite-scroll-disabled="busy" infinite-scroll-distance="10">
            <tbody id="trans-table">
                <tr v-for="transaction in transactions" v-model="transactions">
                    <td v-for="item in transaction" v-html="item"></td>
                </tr>
            </tbody>
        </table>
    </template>
    
    <script>
        import Search from './Search.vue';
    
        export default {
            components: {
                Search
            },
            data() {
                return { 
                    transactions: [], 
                    currentPosition: 0 
                }
            },
            methods: {
                loadMore() {
                    this.$root.$emit('loadMore', {
                        currentPosition: this.currentPosition
                    });
                }
            }
        }
    </script>
    

    As You can see loadMore is triggered on infinite scroll and event is being sent to child component search. Well not just search but since it's root it's being broadcast to everyone.

    What is better approach for this. I know that i should use props but I'm not sure how can i do that in this situation.

    • Potray
      Potray over 6 years
      You can emit directly in the children using this.$children[index].$emit: vuejs.org/v2/api/#vm-children
    • Roy J
      Roy J over 6 years
      Is the Search component the child, and is it something you can add a prop to?
    • madeye
      madeye over 6 years
      @RoyJ Yes Search is a child as you can see here in code i provided in line number 2 <search></search> template and I can add a prop but that was my question how can i use prop to emit loadMore?
  • madeye
    madeye over 6 years
    That would definitely work but it feels a little hacky.
  • Mike R
    Mike R about 3 years
    Good answer in my book. Wouldn't call this hacky, it's literally just making use of the event-bus pattern with a small vue object as a base.
  • tobiasBora
    tobiasBora about 3 years
    I would recommend to also remove the listener when the state is destroyed, as explained here digitalocean.com/community/tutorials/vuejs-global-event-bus, otherwise you may get strange bugs if your objects is destroyed and recreated as the listeners of the old object will still be alive! (Just got this annoying bug) To destroy your listener, name your callback function, and then do beforeDestroy: function() {this.bus.$off('loadMore', nameOfCallback);}