Reputation: 18411
I have an element that being conditionally rendered with v-if="isLogged"
, if a user is logged in:
<div
v-if="isLogged"
class="chatBlock"
ref="chat"
></div>
I'm trying to get scroll height of the chat
reference in a mounted ()
function - this.$refs.logged.scrollHeight
, but it's not possible, because if a user is not logged in, then this div
won't be rendered on a mounting stage, so even if a user logs in - it won't work, because mounted stage already passed.
Is it possible to track element appearance in a DOM using watch
method?
UPDATE
Added watcher, as Steven suggested below in a mounted ()
:
this.$store.watch(
(state) => {
return this.$store.getters.isLogged
},
(newValue, oldValue) => {
if (newValue) {
this.chatHeight = this.$refs.chat.scrollHeight
}
}
)
Upvotes: 12
Views: 24555
Reputation: 3125
Try adding a nexTick around the call to the ref
. This way, the ref
will exist when the code enters the block.
Demo:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.4.8/vue.global.min.js"></script>
<div id="app">
<div>
<button @click="handleToggle" style="margin-right:0.5rem;">Toggle</button>
<my-element v-if="visible" ref="myElement" />
</div>
</div>
<script>
const {
createApp
} = Vue
createApp({
components: {
myElement: {
template: "<span>{{ text }}</span>",
data() {
return {
text: '',
};
},
}
},
data() {
return {
visible: false,
}
},
methods: {
handleToggle() {
this.visible = !this.visible;
if (this.visible) {
this.$nextTick(() => {
this.$refs.myElement.text = "I'm visible";
});
}
},
}
}).mount('#app')
</script>
Upvotes: 0
Reputation: 1748
Switching to v-show
, as suggested by Steven, worked for me. It was actually the better option because v-show
is cheap to toggle, unlike v-if
, see this answer: https://stackoverflow.com/a/44296275/2544357
Upvotes: 1
Reputation: 2830
The accepted answer did not work for me. The watch does not guarantee that the element has already been rendered.
To make sure that the element is available, I had to use $nextTick
if (newValue) {
this.$nextTick(function () {
this.chatHeight = this.$refs.chat.scrollHeight
})
}
This will cause the code to be executed after the next DOM update cycle.
Upvotes: 18
Reputation: 29169
Add a watch to isLogged
. When it is active, get your chat
ref. You will also have to check on your mounted
, so put your logic in a common function.
So in your component:
val componentOptions = {
methods: {
checkDiv() {
const chatDiv = this.$refs.chat
if (chatDiv) {
// your code here...
}
}
},
mounted() {
this.checkDiv();
},
watch: {
isLogged(value) {
if (value) {
this.checkDiv()
}
}
}
}
—-
You can also use v-show
instead of v-if
. That way your element will be rendered but hidden.
Upvotes: 6