Our website is made possible by displaying online advertisements to our visitors. Please consider supporting us by disabling your ad blocker.

Access And Change Parent Variables From A Child Component With Vue.js

TwitterFacebookRedditLinkedInHacker News

When working with single page web applications (SPA), chances are you’re going to be using a router or some kind of parent and child component structure. In these scenarios, the parent components probably hold their own functions and variables that may at some point in time need to be accessed by the child component. Take for example an application that has authentication. The parent component might manage the authentication state while the child component might be a login form, secure content, or something else. When logging in, you might need to change the authentication state of the parent. This is just one of many possible examples where the child and parent need to interact.

We’re going to see how to interact with a parent component from a child component in an application created with the Vue.js JavaScript framework.

Create a New Vue.js Web Application

For this example, we’re going to be creating a fresh project with the Vue CLI. Assuming you’ve installed the Vue CLI, execute the following:

vue create test-project

When asked, choose to manually select features. The only feature we want for this example is the Router from the list of features. We want the router because we want to know how to access container variables. On the next prompt, it doesn’t matter how you plan to manage configurations.

At this point we should have a functional project to work with.

Accessing the Variables and Functions with the $parent Attribute

In the fresh project, there will be many files, but we only care about the src/App.vue and src/views/Home.vue files. No need to create something complicated or fancy out of this simple example.

Open the src/App.vue file and make it look like the following:

<template>
    <div id="app">
        <div id="nav">
            <router-link to="/">Home</router-link> |
            <router-link to="/about">About</router-link>
        </div>
        <p>{{ msg }}</p>
        <router-view />
    </div>
</template>

<script>
    export default {
        name: 'App',
        data() {
            return {
                msg: "Hello World"
            }
        }
    }
</script>

<style></style>

Our goal will be to retrieve and alter the msg variable in this parent component. Now open the project’s src/views/Home.vue file which is a view that is loaded in the <router-view /> line of the src/App.vue file.

<template>
    <div class="home">
        <img src="../assets/logo.png">
        <HelloWorld msg="Welcome to Your Vue.js App"/>
        <button class="button" v-on:click="changeMsg()">Change Message</button>
    </div>
</template>

<script>
    // @ is an alias to /src
    import HelloWorld from '@/components/HelloWorld.vue'

    export default {
        name: 'home',
        components: {
            HelloWorld
        },
        method: {
            changeMsg() {
                this.$parent.msg = "I changed the message";
            }
        }
    }
</script>

Most of the above code was provided when generating our project, but take notice of the changeMsg function. When the button is pressed in this child component, the changeMsg function is called and the msg variable is directly manipulated from the parent component. We can get or set the msg variable using this strategy.

Now let’s look at an alternative, which many say is the better solution.

Emitting Data to the Parent Component with the $emit Attribute

Instead of directly accessing the variable through the $parent attribute, we’re going to be communicating with the parent component through events. In other words, we’re going to emit an event from our child and listen for it in the parent.

Open the project’s src/App.vue file and include the following:

<template>
    <div id="app">
        <div id="nav">
            <router-link to="/">Home</router-link> |
            <router-link to="/about">About</router-link>
        </div>
        <p>{{ msg }}</p>
        <router-view @message="setMessage" />
    </div>
</template>

<script>
    export default {
        name: 'App',
        data() {
            return {
                msg: ""
            }
        },
        methods: {
            setMessage(msg) {
                this.msg = msg;
            }
        }
    }
</script>

<style></style>

Notice that this time around, our <router-view> tag has changed. Now we’re listening for a message event and if heard, we call the setMessage callback method. In the callback method, we set the parent msg variable with the data that was sent.

Open the project’s src/views/Home.vue file and include the following:

<template>
    <div class="home">
        <img src="../assets/logo.png">
        <HelloWorld msg="Welcome to Your Vue.js App"/>
        <button class="button" v-on:click="changeMsg()">Change Message</button>
    </div>
</template>

<script>
    // @ is an alias to /src
    import HelloWorld from '@/components/HelloWorld.vue'

    export default {
        name: 'home',
        components: {
            HelloWorld
        },
        method: {
            changeMsg() {
                this.$emit("message", "I changed the message");
            }
        }
    }
</script>

Instead of using the $parent property, we’re now using the $emit property. We are emitting data as the message event which we’re currently listening for in our parent component.

Pretty awesome right?

Conclusion

You just saw how to interact with a parent component via a child component using two different approaches. We saw how to use $parent and $emit, both of which serve in usefulness for different scenarios.

What I demonstrated isn’t strictly useful when using a router. Both approaches can be used without the router as well.

Nic Raboy

Nic Raboy

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in C#, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Unity. Nic writes about his development experiences related to making web and mobile development easier to understand.