app global property doesnt work when used inside script - vue.js

So I am using Lang plugin. This is how I install it:
onDomReady(() => {
appVue.use(Lang, {
lang: langService._lang,
});
appVue.mount('#app');
});
And this is install code for Lang:
const plugin = {
install(app, options) {
if (!app.config.globalProperties.hasOwnProperty('$lang')) {
app.config.globalProperties.$lang = options.lang;
}
app.config.globalProperties.$t = function (key, opt) {
const lang = this.$lang;
return lang.trans(key, opt);
};
},
};
export default plugin;
So now I should be able to access $t and $t works when it is used inside template tags for example.
<template>
<div>{{ $t('hello') }}<div>
<template>
It prints out translation, but when I use inside <script> tag for example:
props: {
placeholder: {
type: String,
default() {
return this.$t('hello');
},
}
}
It throws me error this.$t is not a function. What is the problem here? Would appreciate some help

Related

Vue3 Composition API PerfectScrollbar Plugin no element is specified to initialize

I'm trying to create a Perfect Scrollbar plugin for Vue3 but i'm stuck on an error when i initialize the object:
Error: no element is specified to initialize PerfectScrollbar
Scrollbar component:
import PerfectScrollbar from 'perfect-scrollbar'
import { isEmpty } from 'lodash'
import {
onMounted,
reactive,
ref,
h
} from 'vue'
export default {
name: 'VuePerfectScrollbar',
props: {
options: {
type: Object,
required: false,
default: () => {
}
},
tag: {
type: String,
required: false,
default: 'div'
}
},
setup(props, {emit, slots}) {
const el = ref(null)
let ps = reactive({})
onMounted(() => {
if (isEmpty(ps)) {
ps = new PerfectScrollbar(el, props.options)
}
})
return () => h(
props.tag,
{
class: 'ps',
ref: el
},
slots.default && slots.default()
)
}
}
I did a console.log right before the initialization and the element reference is there, so i'm not sure why the error pops up. According to this This error simply means that you are calling PerfectScrollbar on something that doesn't exist! so maybe the DOM hasn't been updated at that moment? I tried with nextTick too but it didn't work.
You should get access to the value attribute in the ref property as follows :
ps = new PerfectScrollbar(el.value, props.options)

vue-pdf doesn't refresh on src change

I'm using the latest vue-pdf package to display pdf files in my app. I built this component, PdfViewer:
<template>
<div class="fill-height pdf-container">
<template v-if="src && numberOfPages">
<pdf
v-for="page in numberOfPages"
:key="`${fileName}-${page}`"
:src="src"
:page="page"
/>
</template>
</div>
</template>
import { mapGetters } from 'vuex'
import pdf from 'vue-pdf'
export default {
props: {
fileName: {
type: String,
required: true
}
},
components: {
pdf
},
data() {
return {
src: null,
numberOfPages: 0
}
},
computed: {
...mapGetters({
getAttachments: 'questions/getAttachments'
})
},
methods: {
init() {
if (this.fileName) {
let url = this.getAttachments[this.fileName]
let loadingTask = pdf.createLoadingTask(url)
this.src = loadingTask
this.src.promise.then(pdf => {
this.numberOfPages = pdf.numPages
})
}
},
},
watch: {
fileName() {
this.init()
}
},
beforeMount() {
this.init()
}
}
Basically I'm receiving a fileName as a prop, then look for its URL in the object I receive in getAttachments getter. The file names are in different list component.
It works fine on the first run and the first file is loaded and displayed successfully. But once clicked on another file name - nothing being displayed. I do receive the file name prop and it does find the URL, but the file doesn't display. Even when I click on the file that has already been displayed - now it doesn't.
I thought maybe it has something to do with src and numberOfPages property, so I tried to reset them before loading the file:
init() {
if (this.fileName) {
this.src = null
this.numberOfPages = 0
let url = this.getAttachments[this.fileName]
let loadingTask = pdf.createLoadingTask(url)
this.src = loadingTask
this.src.promise.then(pdf => {
this.numberOfPages = pdf.numPages
})
}
}
Alas, same result. And in the console I see the following warning from pdf.worker.js: Warning: TT: invalid function id: 9
Have no idea what it means.
Any help, please?
EDIT
I tried to do that with async/await and forceUpdate:
async init() {
if (this.fileName) {
this.src = null
this.numberOfPages = 0
let url = this.getAttachments[this.fileName]
let loadingTask = await pdf.createLoadingTask(url)
await loadingTask.promise.then(pdf => {
this.src = url
this.numberOfPages = pdf.numPages
})
this.$forceUpdate()
}
}
That also didn't help. But I found out that once I change the passed fileName, the code does go to the init() method, but for some reason it skips the loadingTask.promise.then part, doesn't go in. I have to idea why.
Well, apparently there's some issue with vue-pdf library. Eventually I solved it by setting timeout when assigning fileName prop and re-rendering the component:
<PdfViewer v-if="selectedFileName" :fileName="selectedFileName" />
onFileNameSelected(fileName) {
this.selectedFileName = null
setTimeout(() => {
this.selectedFileName = fileName
}, 0)
}
And then in the PdfViewer component it's just:
created() {
this.src = pdf.createLoadingTask(this.getAttachments[this.fileName])
},
mounted() {
this.src.promise.then(pdf => {
this.numberOfPages = pdf.numPages
})
}
That did the trick for me, though feels kinda hacky.

How to use the Vue component $set to set object in single file component

Following Vue.js tutorial, I read this part here https://v2.vuejs.org/v2/guide/list.html#Object-Change-Detection-Caveats:
var vm = new Vue({
data: {
userProfile: {
name: 'Anika'
}
}
})
// It was stated in the tutorial that, the below will add to userProfile
// while making sure userProfile still being reactive
vm.$set(vm.userProfile, 'age', 27)
Nice, would like to try that vm.$set function.
However, my implementation is in a single file component, e.g. something like this:
<script>
export default {
name: 'Test',
data() {
return {
userProfile: {
name: 'Anika'
}
};
}
}
</script>
How would I be able to retrive the vm variable above? I have tried the following code but didn't work... With error:
vm.$set is not a function
<script>
let vm = {
name: 'Test',
data() {
return {
userProfile: {
name: 'Anika'
}
};
}
}
vm.$set(vm.userProfile, 'age', 27)
export default vm;
</script>
if you use it inside the context of your component, you just
this.$set(this.userProfile,....)

Calling API in method and getting [object Promise]

I'm using Nuxt.js in static site mode, and trying to get an image from an API using a string passed in a prop, however, in the template I am getting [object Promise]. I would've thought that return before the get request would resolve the promise, but I think my grasp of promises and Nuxt.js a little off. Any help would be greatly appreciated.
<template>
<div>
{{ getThumbnailSrc() }}
</div>
</template>
<script>
import axios from 'axios'
export default {
props: {
link: {
type: String,
required: true
}
},
data() {
return {
imageUrl: null
}
},
methods: {
getVimeoId(link) {
return link.split('/').pop()
},
getThumbnailSrc() {
return axios
.get(
`https://vimeo.com/api/v2/video/${this.getVimeoId(
this.link
)}.json`
)
.then(response => {
const vimeoThumbnailUrl = response.data[0].thumbnail_large
console.log(vimeoThumbnailUrl)
return {
vimeoThumbnailUrl
}
})
.catch(error => {
console.log(error)
})
}
}
}
</script>
It sure won't! XHR requests are asynchronous and therefore the template has no idea that it needs to wait.
Solve it by using an additional data property on the component, and using that instead:
data() {
return {
imageUrl: null,
thumbnailSrc: null
}
},
And in your callback:
.then(response => {
const vimeoThumbnailUrl = response.data[0].thumbnail_large
console.log(vimeoThumbnailUrl)
this.thumbnailSrc = vimeoThumbnailUrl
})
Now you can use {{thumbnailSrc}} and it will load appropriately.

Async changes to properties

New to vuejs.
I have a vue with the following script (code shortened):
export default {
mixins: [asyncStatuses],
props: {
value: { type: Object }
},
data() {
return {
statuses: []
};
},
computed: {
hasStatuses() {
return this.statuses && this.statuses.length > 0;
}
},
beforeMount() {
// This is an async call
this.getStatuses().then((response) => {
this.statuses = response.data.statuses;
});
}
};
In my .vue file, I do something like this:
<div v-if="hasStatuses">
<div>Show a list of statuses</div>
</div>
The problem is the <div> never shows up. The statuses are loading correctly. I put a debugger in the computed.hasStatuses but it never runs?
Can anyone explain to me how and why this is happening and how to fix it?
Thanks again!!
The code is setting self.statuses, but self is not defined.
self.statuses = response.data.statuses
Just use this.
this.statuses = response.data.statuses