How do I stop my vue component from rendering until a call completes - vue.js

I've googled this but I can't find any specific solution. Basically I have a vue component that depends on an init call and I want it to stop rendering until the call completes, at which point I want the component to render. Seems simple but unless I'm missing something I can't find any lifecycle method that does that.

You can use v-if for that purpose
<template>
<div v-if="loaded"></div>
</template>
<script>
export default {
name: 'TestComponent',
data: function () {
return {
loaded: false
}
},
created() {
callExternalServices().then(() => {
this.loaded = true
})
}
}
</script>
It will render an empty component until loaded == true

Basically you make an init call in the created or mounted lifecycle method and you initialize a data object with the response of the call. If you don't change data during the call there is no reason for vue to render anything.
Maybe you can provide a jsfiddle that show exactly your problem.

Related

Vue js component template not updating with data

I have a weird issue in some of my Vue js components, let me explain. I only render my component template after data has been initialised like so:
<template>
<div>
<div v-if='!isLoading'>
<!-- content -->
</div>
<div v-else>...</div>
</div>
</template>
In the created method of this component, I get some data from the store and set isLoading to false like so.
data() {
return {
variable: null,
isLoading: true,
}
},
created() {
this.variable = this.$store.getters['someModule/someGetter']
this.isLoading = false
}
Here's where the weird behaviour happens. Even though I updated the isLoading variable to false in the created method, the component template is not updating.
When I log the isLoading variable to the console at the end of the created method, it logs false, like i set it. But when I check the isLoading variable in the Vue js tools, it's still set to true...
Lets say this components is rendered in '/content'. This weird behaviour happens when I change routes from '/' to '/content'. When I refresh the app on the '/content' route, this doesn't happen. When I go from '/' to '/other-content' and then to '/content' it also doesn't happen.
Any ideas on why this happens would be greatly appreciated.
Thanks is advance and have a nice day!
There are subtle differences between mounted and created in your case since you want to manipulate the DOM, you should use mounted lifecycle hook.
This answer would expound on the differences between the two lifecycle methods.
This is a working example of what you're trying to do: https://codesandbox.io/s/blissful-field-kjufc?file=/src/App.vue
The interesting part of the code is here:
async created() {
const response = await fetch("https://jsonplaceholder.typicode.com/photos");
const json = await response.json();
console.log("done loading the data");
if (json) this.isLoading = false;
},
You can go to your network tab and select "slow 3G" to have an emulated slow connection. That way, you will see that the VueJS logo is not displayed until we have fetched all the 5000 photos.
If it's not helping, we definitely need more details, like vue devtools debugging or a reproduction.

Detect exiting route changes in Vue

I'm working on a component which enables the user to undo the deletion of an item. However, the item should be deleted when the user navigates to another route. To achieve this I'm watching the route like so:
`watch: {
$route(to, from) {
if (this.showUndo === true) {
console.log('item will be deleted');
this.confirmDelete();
}
},
},
`
Unfortunately, this gets only triggered when I enter this specific route and not on exiting it. An explanation why that is or an alternative to my watch: - method would be much appreciated!
Basically I'm looking for an alternative to beforeRouteLeave since this is a sub-component and therefore I can't use Navigation Guards. Thanks!
Vue lifecycle hook- BeforeDestroy is fired right before teardown. Your component will still be fully present and functional. If you need to cleanup events or reactive subscriptions,
beforeDestroy would probably be the time to do it.
<script>
export default {
beforeDestroy() {
//Try like this
this.confirmDelete();
console.log('item will be deleted');
}
}
</script>
Ref - https://v2.vuejs.org/v2/api/#beforeDestroy

How to write a single piece of code running both on route A (mounted hook) and also when arriving at route A?

Currently in order for me to do a thing X either when loading route A or arriving to route A, I need to write X twice:
watch: {
$route (to, from){
if (to.name === 'simulation-step-3-sequence') {
EventBus.$emit('actionIsSortable');
}
}
},
async mounted () {
if (this.$route.name === 'simulation-step-3-sequence') {
EventBus.$emit('actionIsSortable');
}
}
Is there a way to simplify this so I write X (the emit line) only once?
This technique is really needed only in two cases - multiple routes are using same component or dynamic routes (with parameters) ...see the docs
In this cases when the new route is using same component as the old route, Vue Router will just reuse existing component instance.
You can place a key on router-view and disable this behavior. Your site will be less effective but you can get rid of $route watcher
<router-view :key="$route.fullPath" />
Other option is to change watcher definition like this:
watch: {
$route: {
immediate: true,
handler: function(to, from) {
console.log(`Route changing from '${from}' to '${to}'`);
}
}
}
Vue will call watcher handler on route changes but also when the component is created (so you can remove the code in lifecycle hook)

Page reload causes Vuex getter to return undefined

Using Vue.js (Vuetify for FE).
A page reload causes the getter in Vuex to fail with pulling required data from the store. The getter returns undefined. The code can be found on GitHub at: https://github.com/tineich/timmyskittys/tree/master/src
Please see the full details on this issue at timmyskittys.netlify.com/stage1. This page has complete info on the issue and instructions on how to view the issue.
Note, there is mention of www.timmyskittys.com in the issue description. This is the main site. timmyskittys.netlify.com is my test site. So, they are the same for all intents and purposes. But, my demo of this issue is at the Netlify site.
I read the complete issue in the website you mentioned. It's a generic case.
Say, for cat details page url: www.timmyskittys.com/stage2/:id.
Now in Per-Route Guard beforeEnter() you can set the cat-id in store. Then from your component call the api using the cat-id (read from getters)
I found the solution to my issue:
I had to move the call of the action which calls the mutation that loads the .json file (dbdata.json) into a computed() within App.vue. This was originally done in Stage1.vue.
Thanks all for responding.
I had the same issue and my "fix" if it can be called that was to make a timer, so to give the store time to get things right, like so:
<v-treeview
:items="items"
:load-children="setChildren"
/>
</template>
<script>
import { mapGetters } from 'vuex'
const pause = ms => new Promise(resolve => setTimeout(resolve, ms))
export default {
data () {
return {
children: []
}
},
computed: {
...mapGetters('app', ['services']),
items () {
return [{
id: 0,
name: 'Services',
children: this.children
}]
}
},
methods: {
async setChildren () {
await pause(1000)
this.children.push(...this.services)
}
}
}
</script>
Even though this is far from ideal, it works.

Vue.js: how to use the afterEnter hook with an async component

I would like to use JS Hook as described here. Specially, I want to use the afterEnter hook with an async component.
This is my async component:
Vue.component('example', function(resolve, reject){
let data = {
text: 'test data',
};
$.post('http://example.com', data, function(r){
r = JSON.parse(r);
if( r.success ) {
resolve({
template: r.data,
afterEnter: function(el, done){
console.log('test');
}
});
}
});
});
This is what the ajax call gets from the server, and it's what is passed to the template in r.data.
<transition v-on:after-enter="afterEnter"></transition>
These are the two errors that I get.
[Vue warn]: Property or method "afterEnter" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
[Vue warn]: Invalid handler for event "after-enter": got undefined
Is it possible to use JS hooks with async components? And if not, how should I approach this? My objective is to run custom JS after Vue (and/or vue-router) inject the component template onto the page, so that I can initiliaze image sliders and whatnot. It is important that my custom JS fires every time the component is navigated to, and not only on the first load.
Thank you.
That warning means that Vue is looking for (but unable to find) a property or method named "afterEnter", which you reference in your template. You have defined afterEnter in your resolve function as if it is a lifecycle hook, but it needs to be one of your Vue instance's methods.
So, your resolve function should look like this:
resolve({
template: r.data,
methods: {
afterEnter: function(el, done) {
console.log('test');
}
}
});