Reputation: 352
I'm trying to get width value from Template and pass the value to child component in vue/nuxt.
However, it doesn't work out. I assume that is because width from template is obtained later stage in life cycle hook.
How could I ensure the width value is obtained first and the child element gets the information?
Parent
<template>
<v-col cols="12" sm="12" md="4" ref="demandContainer">
<div class="chart-container p-4 dark-background">
<div class="font-weight-bold">Demand</div>
<area-chart
v-if="trendsData.length > 0"
:data="trendsData"
:baseWidth="width"
>
</area-chart>
</div>
</v-col>
</template>
<script>
export default {
updated() {
this.width = this.$refs.demandContainer.$el.clientWidth
},
}
</script>
Child
<svg ref="svg-area" :width="baseWidth" :height="baseHeight">
</svg>
Upvotes: 1
Views: 496
Reputation: 46774
Refs are available only once the component is mounted
to the actual DOM.
In created, it is created somewhere but not yet appended to your page.
The issue as explained here is that you may have some issues to pass it to the child component since child's mounted
lifecycle hook will happen before the parent's one.
I've tried some super hacky things
async mounted() {
await this.$nextTick()
this.$watch(
() => {
return this.$refs.test.$el.clientWidth
},
(val) => {
console.log('nice', val)
},
)
},
It did not work because clientWidth
would be available at an even later point (lifecycle-wise). So, the last solution is probably to use some even more ugly setTimeout
.
Or you could fix the issue with CSS, it will be:
Because SVG are meant to be super responsive and easy to work with.
Can you show us what you want to do with your SVG?
TLDR: don't use JavaScript to solve a responsive issue here. Having to work with parent
+ child
+ mounted
lifecycles is not a good idea usually.
Upvotes: 0
Reputation: 2871
for the $refs
to work you should make sure the template is fully rendered to the DOM
and to do this you can have this code in the mounted
hook:
mounted() {
this.$nextTick(() => { this.width = this.$refs.demandContainer.$el.clientWidth; });
}
according to vue doc for $nextTick
:
vm.$nextTick( [callback] ): Defer the callback to be executed after the next DOM update cycle. Use it immediately after you’ve changed some data to wait for the DOM update. This is the same as the global Vue.nextTick, except that the callback’s this context is automatically bound to the instance calling this method.
so with the help of $nextTick
you can make sure the element is rendered to DOM
to use the ref
defined on the element.
Edit
actually it is $el
thats undefined
. this.$refs.demandContainer
returns the element itself and to get the width you can just have this.$refs.demandContainer.clientWidth
.
check the example below:
new Vue({
el: '#app',
vuetify: new Vuetify(),
mounted() {
console.log(this.$refs.demandContainer.clientWidth);
},
})
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.js"></script>
<div id="app">
<v-app>
<v-main>
<v-container>
<v-col cols="12" sm="12" md="4" ref="demandContainer">
<div class="chart-container p-4 dark-background">
<div class="font-weight-bold">Demand</div>
</div>
</v-col>
</v-container>
</v-main>
</v-app>
</div>
Upvotes: 0