In this article, we’ll look at how to access various parts of a parent, child, or root component. Also, we look at dependency inject in Vue.js
Element & Component Access
Sometimes we have to access other components from a given component. However, it’s a bad idea to do this often since it gets messy fast.
Accessing the Root Instance
We can access the root instance of from a child component with the $root
property.
For example, we can access the root Vue instance’s foo
property as follows:
src/index.js
:
Vue.component("foo", {
template: `<p>{{rootFoo}}</p>`,
computed: {
rootFoo() {
return this.$root.foo;
}
}
});
new Vue({
el: "#app",
data: {
foo: "bar"
}
});
index.html
:
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<foo></foo>
</div>
<script src="src/index.js"></script>
</body>
</html>
The code above created a rootFoo
computed property from the root Vue instance’s foo
component and displayed it inside the foo
component.
So we get foo
displayed.
The data returned from $root
can also be set and its methods can so be called.
So we can write:
this.$root.foo = 2
or:
this.$root.baz()
from any subcomponent in addition to accessing the properties’ values.
Accessing the Parent Component Instance
Similar to $root
, we can access the parent component’s properties with the $parent
property from a child component.
This shouldn’t be used frequently because it’s hard to trace when the parent’s data was set, so we should pass in props to the child instead of accessing the $parent
property directly.
For example, we can use it as follows:
src/index.js
:
Vue.component("child", {
template: `<p>{{parentFoo}}</p>`,
computed: {
parentFoo() {
return this.$parent.foo;
}
}
});
Vue.component("parent", {
data() {
return {
foo: "bar"
};
},
template: `
<p><slot></slot></p>
`
});
new Vue({
el: "#app"
});
index.html
:
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<parent>
<child></child>
</parent>
</div>
<script src="src/index.js"></script>
</body>
</html>
In the code above, we accessed the parent
component’s foo
property from the child
component by using this.$parent
in the computed property parentFoo
. So, we get bar
displayed on the screen.
Accessing Child Component Instances & Child Elements
We can access a child component directly in JavaScript. To do this, we can add a ref
attribute to the child component and assign a name as the value.
Then we can use this.$refs.name
to access the component where name
is the name that we set.
For example, we can use it as follows:
src/index.js
:
new Vue({
el: "#app",
mounted() {
this.$refs.input.focus();
}
});
index.html
:
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input ref="input" />
</div>
<script src="src/index.js"></script>
</body>
</html>
In the example above, we added a ref
with name input
in the template and then we accessed the input element with:
this.$refs.input
And then called focus
on it in the mounted
hook.
This lets us focus the input as soon as the input element has loaded.
We can also access a child component’s methods as follows:
src/index.js
:
Vue.component("base-input", {
methods: {
focus() {
this.$refs.input.focus();
}
},
template: `<input ref='input' />`
});
new Vue({
el: "#app",
mounted() {
this.$refs.baseInput.focus();
}
});
index.html
:
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<base-input ref="baseInput"></base-input>
</div>
<script src="src/index.js"></script>
</body>
</html>
In the code above, our root Vue instance called base-input
‘s focus
method when it’s mounted.
Therefore, we see that the input is in focus when base-input
loaded.
Dependency Injection
To prevent accessing the parent component and root Vue instance directly, we can use dependency injection to get the component that we want to get.
We can use it as follows:
src/index.js
:
Vue.component("foo-button", {
methods: {},
inject: ["toggleFoo"],
template: `<button @click='toggleFoo'>Toggle Foo</button>`
});
new Vue({
el: "#app",
data: {
foo: ""
},
provide() {
return {
toggleFoo: this.toggleFoo
};
},
methods: {
toggleFoo() {
this.foo = this.foo === "foo" ? "" : "foo";
}
}
});
index.html
:
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<foo-button></foo-button>
{{foo}}
</div>
<script src="src/index.js"></script>
</body>
</html>
In the code above, we added the provide
method to return an object with the items that we want to make available to child components.
We made the toggleFoo
method from the root Vue instance available to our foo-button
component.
Then in the foo-button
component, we injected the toggleFoo
method from the parent to foo-button
and then we call it when click events are triggered on the button.
We included foo-button
in the template as usual.
In the end, we should see that we toggle the word foo
on the screen when we click on the button.
Conclusion
We can access the root Vue instance with $root
, and the parent component with $parent
.
To access a child component from a parent, we can assign a ref
with a name to the child component and then use this.$refs
to access it.
These properties shouldn’t be used too often because they create a mess fast.
To keep accessing external components clean and traceable, we can use dependency injection by defining the provide
method to expose certain parts of a component and use inject
to get the provided parts.