I understand that Vue will re-render when the data changes. But when I change the data in a hook function like mounted, the page does not re-render. Below is part of my code.
mounted: function () {
document.getElementById('lanchange').onclick = function (e) {
this.loginPopActive = false
this.lanPopActive = false
console.log(this.lanPopActive)
}
}
The code has an issue with this. Use an arrow function, a closure, or bind.
mounted: function () {
document.getElementById('lanchange').onclick = (e) = >{
this.loginPopActive = false
this.lanPopActive = false
console.log(this.lanPopActive)
}
}
Related
I need to use computed property in my Category Layout page. When pages which are under this layout changed, computed must understand page changings. But I can't catch these changes and I can only catch changes if I use them in Watch property.
Layout.vue
v-app
v-main
nuxt
speed-dial-button(:page="page")
....
setup() {
const route = useRoute();
const page = ref('');
const currentPath = computed(()=>route.value.path);
if (['/eserler', '/en/artworks', '/ar/artworks'].includes(currentPath)) {
page.value = i18n.t('general.addNewArtwork');
} else if (['/kisiler', '/en/persons', '/ar/persons'].includes(currentPath)) {
page.value = i18n.t('general.addNewPerson');
} else if (['/etkinlikler', '/en/activities', '/ar/activities'].includes(currentPath)) {
page.value = i18n.t('general.addNewActivity');
}
console.log('page',page)
console.log('route',routePath)
return {
page,
};
}
This will work if I load page first time or if I leave layout and return again .
Your template will react, but not your log statement. Put that in a watcher. Set deep and immediate to your needs.
watch(route, value => {
// your code here
console.log(value.path)
}, {deep: true, immediate: true})
First of all, I am a new vuejs developer and my purpose is to get acquainted with Vue, so, not going to use any external plugins or components.
I am writing a simple alert component, which looks like this:
<Alert :show="showAlert" />
I want the show property to return back to false after 2 seconds. How can I do this from inside the component (i.e., not in the page where this component is used). I tried this:
import { computed } from 'vue';
export default {
props: ['show'],
setup(props) {
const shown = computed(() => {
if (props.show) {
setTimeout(() => {
console.log("hiding the alert...")
props.show = false
}, 2000);
}
return props.show.value
})
return { shown }
}
};
the compiler said:
14:15 error Unexpected timed function in computed function vue/no-async-in-computed-properties
16:19 error Unexpected mutation of "show" prop vue/no-mutating-props
My rational is that the delay of alert should be controlled by the alert component (which could be changed by a prop), but not forcing the caller to write some thing like:
function Alert(delay) {
showAlert = true
setTimeout(() => showAlert = false, delay)
}
There are 2 errors.
First vue/no-mutating-props, props are read only so you are not supposed to change it from within the component. It is still possible to change props from outside the component and pass down to it.
For this you should copy the value of props to your data()
data() {
return {
showAlert
}
}
You should be able to update showAlert with no problem.
The second error vue/no-async-in-computed-properties, you cannot write async function inside computed(), so the alternative is to use watch instead.
I have a vue code where i do some actions based on this.$refs.form.validate
I wanted to write a test for it ...But not sure how can i mock this.$refs.form.validate? I have written only basic ones..can someone point me at right direction?I am using Vue+Jest
methods: {
sayHello () {
if (this.$refs.form.validate()) {
//code goes here
}
Is there a way to make it return false and true?
create a stub
const VueFormStub = {
render: () => {},
methods: {
validate: () => {}
}
}
then in your wrapper add it like this
const wrapper = shallowMount(VueFile, {
stubs: {
'v-form': VueFormStub
}
})
What is strange $refs don't seem to work inside mocks property when we mount a component in a test. But if we do like this it works
const wrapper = mount(SidePanel);
wrapper.vm.$refs.checkbox = [{ focused: false }, { focused: true }];
So when component does something like this it will be ok
console.log(this.$refs.checkbox[0].focused);
You need to use jest method jest.fn() to mock your function. Like so const foo = jest.fn(). And the you need to test, if this fn has been called.
I'm trying to render my DOM, dependent on some data I'm returning from an axios get. I can't seem to get the timing right. The get is in the created hook, but there is a delay between the get and actually receiving the data. Basically if there is info in seller_id then I need to show the cancel button, otherwise don't. Here is my code:
this is in my created hook
axios.get('https://bc-ship.c9users.io/return_credentials').then(response => {
this.seller_id = response.data.seller_id;
this.selected_marketplace = response.data.marketplace;
this.token = response.data.auth_token;
});
and then this is the logic to show or hide the button. I've tried created, mounted, beforeUpdate, and updated all with no luck. I've also tried $nextTick but I can't get the timing correct. This is what I have currently:
beforeUpdate: function () {
// this.$nextTick(function () {
function sellerIdNotBlank() {
var valid = this.seller_id == '';
return !valid;
}
if(sellerIdNotBlank()){
this.show_cancel_button = true;
}
// })
},
First, it is pointless to get your data from backend and try to sync with Vue.js lifecycle methods. It never works.
Also, you should avoid beforeUpdate lifecycle event. It is often a code smell. beforeUpdate is to be used only when you have some DOM manipulations done manually and you need to adjust them again before Vue.js attempt to re-render.
Further, show_cancel_button is a very good candidate for a computed property. Here is how component will look:
const componentOpts = {
data() {
return {
seller_id: '',
// ... some more fields
};
},
created() {
axios.get('https://bc-ship.c9users.io/return_credentials').then(response => {
this.seller_id = response.data.seller_id;
this.selected_marketplace = response.data.marketplace;
this.token = response.data.auth_token;
});
},
computed: {
show_cancel_button() {
return this.seller_id !== '';
}
}
}
I have a function in my Vue app which takes some time (about 2-3 seconds) to complete. It is not an AJAX call.
I would like to include a loading indicator while this code executes, but I am having trouble accomplishing it. I thought I could do the following...
<div v-on:click="doThings()">{{stuff}}</div>
methods: {
doThings: function () {
this.loading = true
console.log(this.loading)
longFunction()
this.loading = false
console.log(this.loading)
}...
}
...but that doesn't work. doThings() seems to not execute anything until longFunction() is done. I even tried making a separate function and changing my button to perform two functions like this...
<div v-on:click="doLoading(); doThings();">{{stuff}}</div>
...but this is also doesn't work. Is what I'm trying to do possible?
Use async code for longFunction() and set this.loading to false after the Promise is resolved.
<div v-on:click="doThings()">{{stuff}}</div>
methods: {
doThings: function () {
this.loading = true
longFunction().then(() => {
this.loading = false
})
}
}
var longFunction = function() {
return new Promise((resolve, reject) => {
window.setTimeout(()=>{ // force a new (pseudo)thread
// do stuff, then
resolve()
},100); // ...some reasonably short interval. One millisecond is working for me when testing locally, but it might be better to include some extra buffer, to ensure Vue is in its next tick
});
}
Alternatively, you could pass an object reference to longFunction that your Vue component can watch for changes on, and use that as the signal back to the component that it can set loading to false.