I'm trying to get the height of the h1 ref element however it is showing as undefined
how can I get the height of my h1 element?
export default {
data() {
return {
h1: null,
};
},
methods: {
getH1Height() {
console.log(this.h1);
},
},
mounted() {
this.$nextTick(() => {
this.h1 = this.$refs.h1;
});
window.addEventListener('resize', () => {
this.getH1Height();
});
},
};
template.js
<h1
ref="h1">
{{ productTitle }}
</h1>
you can try :
this.$refs.h1.offsetHeight
Related
I have a table and I give a ref to it.
<table ref="table"></table>
I want to calculate the height of this table in watcher:
watch: {
buttonClicked: {
immediate: true,
handler() {
this.$nextTick(() => {
const tableElement = this.$refs.table.$el;
const tableOffsetTop = tableElement.getBoundingClientRect().top;
});
},
},
}
But I am getting an error: Uncaught TypeError: Cannot read properties of undefined (reading '$el')
I tried ti fix it with this.$nextTick but this time I cannot calculate it right.
How can I fix it?
Try without $el:
const app = Vue.createApp({
data() {
return {
height: null
}
},
watch: {
buttonClicked: {
handler() {
this.$nextTick(() => {
const tableElement = this.$refs.table;
const tableOffsetTop = tableElement.getBoundingClientRect().top;
this.height = tableElement.getBoundingClientRect().bottom -tableElement.getBoundingClientRect().top
});
},
immediate: true,
},
}
})
app.mount('#demo')
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>
<div id="demo">
<table ref="table"><tr><td>table</td></tr></table>
height: {{ height }}
</div>
I am trying to build a component that should update the string using setInterval.
Here is the code of the component.
<script>
export default {
data() {
return {
offers: [
'1!',
'2!',
'3!',
],
current_index: 0,
indexInterval: null,
}
},
created() {
this.updateToastIndex()
},
beforeDestroy() {
clearInterval(this.indexInterval)
},
methods: {
updateToastIndex() {
const indexInterval = setInterval(() => {
this.$nextTick(() => {
if (this.current_index === 2) {
this.current_index = 0
console.log(this.offers[this.current_index], 'changedprev')
} else {
this.current_index = this.current_index + 1
console.log(this.offers[this.current_index], 'changed')
}
})
}, 1000)
this.indexInterval = indexInterval
},
},
}
</script>
<template>
<div>{{ offers[current_index] }}</div>
</template>
I can see the current_index in updateToastIndex function getting updated but current_index in template is not getting updated.
Please suggest some solution
I am using buefy taginput in my form, everything works as expect filter using ontype event.
only problem here is that i can see data in taginput box on when i focus, its getting selected too, but when i type its not getting filtered. for 10-15 items its not a problem but when its 1000+ items, it will be difficult. i don't know whats the problem here.
here is code so far.
<template>
<b-field label="Popular Destinations">
<b-taginput
v-model="form.popularSubDests"
:data="allSubDests"
autocomplete
:allow-new="allowNew"
:open-on-focus="openOnFocus"
field="SubDestName"
icon="label"
placeholder="Add Cities"
#typing="getFilteredSubdest"
>
</b-taginput>
</b-field>
</template>
<script>
export default {
data() {
return {
openOnFocus: false,
isSelectOnly: false,
allowNew: false,
allSubDestinations: [],
form: {
popularSubDests: [
{
SubDestName: null,
SubDestId: null,
},
],
},
}
},
computed: {
allSubDests() {
return this.allSubDestinations.map((item) => ({
SubDestId: item.id,
SubDestName: item.subdestname,
}))
},
},
methods: {
getFilteredSubdest(text) {
this.allSubDests = this.allSubDests.filter((option) => {
return option.SubDestName.toString().toLowerCase().indexOf(text.toLowerCase()) >= 0
})
},
},
async asyncdata({ route }) {
let { data: allSubDest } = await axios.get(`process.env.FETCHSUBDEST`)
return {
allSubDestinations: allSubDest.results,
}
},
}
</script>
I'm using CKEditor 5 + CKFinder (Modal Mode) to select an image using the #click event. The problem is that I don't have access to data inside the onInit function.
Here is the method:
data() {
return {
post: {
thumbnail: null,
},
};
},
methods: {
openModal() {
console.log(this.post.thumbnail) // NO PROBLEM! this.post.thumbnail IS ACCESSIBLE
CKFinder.modal( {
chooseFiles: true,
width: 800,
height: 600,
onInit: function( finder ) {
finder.on( 'files:choose', function( evt ) {
var file = evt.data.files.first();
this.post.thumbnail = file.getUrl(); // PROBLEM !! $this.post is undefined
} );
}
} );
},
},
And this is my Template:
<div class="btn btn-danger" #click="openModal">Choose Image</div>
<img class="mx-auto d-block" :src="post.thumbnail" />
As mentioned in the comment, you need to use an arrow function to resolve this in the vue object.
Whenever you use function () {}, this refers to the properties of the function, not the Vue object that you intend to reference
// example
methods () {
openModal() {
onInit: function () {
this.post // 'this' is the onInit function, not the Vue object
}
}
}
// solution
methods () {
openModal() {
onInit: () => {
this.post // 'this' is the Vue object
}
}
}
Answer
data() {
return {
post: {
thumbnail: null,
},
};
},
methods: {
openModal() {
console.log(this.post.thumbnail) // NO PROBLEM! this.post.thumbnail IS ACCESSIBLE
CKFinder.modal( {
chooseFiles: true,
width: 800,
height: 600,
onInit: finder => {
finder.on( 'files:choose', evt => {
var file = evt.data.files.first();
this.post.thumbnail = file.getUrl(); // PROBLEM !! $this.post is undefined
});
}
});
},
},
How can I fix this error "Computed property "main_image" was assigned to but it has no setter"?
I'm trying to switch main_image every 5s (random). This is my code, check created method and setInterval.
<template>
<div class="main-image">
<img v-bind:src="main_image">
</div>
<div class="image-list>
<div v-for="img in images" class="item"><img src="img.image"></div>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'Item',
data () {
return {
item: [],
images: [],
}
},
methods: {
fetchImages() {
axios.get(`/api/item/${this.$route.params.id}/${this.$route.params.attribute}/images/`)
.then(response => {
this.images = response.data
})
.catch(e => {
this.images = []
this.errors.push(e)
})
},
},
computed: {
main_image() {
if (typeof this.item[this.$route.params.attribute] !== 'undefined') {
return this.item[this.$route.params.attribute].image_url
}
},
},
watch: {
'$route' (to, from) {
this.fetchImages()
}
},
created () {
axios.get(`/api/item/${this.$route.params.id}/`)
.then(response => {
this.item = response.data
})
.catch(e => {
this.errors.push(e)
})
this.fetchImages();
self = this
setInterval(function(){
self.main_image = self.images[Math.floor(Math.random()*self.images.length)].image;
}, 5000);
},
}
</script>
Looks like you want the following to happen...
main_image is initially null / undefined
After the request to /api/item/${this.$route.params.id}/ completes, it should be this.item[this.$route.params.attribute].image_url (if it exists)
After the request to /api/item/${this.$route.params.id}/${this.$route.params.attribute}/images/ completes, it should randomly pick one of the response images every 5 seconds.
I'd forget about using a computed property as that is clearly not what you want. Instead, try this
data() {
return {
item: [],
images: [],
main_image: '',
intervalId: null
}
},
methods: {
fetchImages() {
return axios.get(...)...
}
},
created () {
axios.get(`/api/item/${this.$route.params.id}/`).then(res => {
this.item = res.data
this.main_image = this.item[this.$route.params.attribute] && this.item[this.$route.params.attribute].image_url
this.fetchImages().then(() => {
this.intervalId = setInterval(() => {
this.main_image = this.images[Math.floor(Math.random()*this.images.length)].image;
})
})
}).catch(...)
},
beforeDestroy () {
clearInterval(this.intervalId) // very important
}
You have to add setter and getter for your computed proterty.
computed: {
main_image: {
get() {
return typeof this.item[this.$route.params.attribute] !== 'undefined' && this.item[this.$route.params.attribute].image_url
},
set(newValue) {
return newValue;
},
},
},