Issue
I’m developing a Django/Vue.js application.
Right after the login form, the Django view redirects to the user/username page, in which the Vue.Js file loads the data from the server. Here is the code:
async created(){
await this.getUpdates();
}
The detail of the getUpdates() function is reported below; basically, it posts at Django the date that the server needs to do its calculations.
async getUpdates(){
await fetch(baseurl + 'getupdates',
{
method: 'post',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRFToken': await this.getCsrfToken()
},
body: JSON.stringify(this.date)
}
);
var response = await this.loadUpdates();
this.updates = await response.json()
},
async loadUpdates(){
await this.getUser();
var response = await fetch(baseurl + 'loadupdates',
{
method: 'post',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRFToken': await this.getCsrfToken()
},
body: JSON.stringify(this.date)
}
);
this.updates = await response.json()
}
The html snippet that uses these updates are reported below
<!--Avvisi-->
<h3>Avvisi:</h3>
<div class="container" >
<div class="row" v-if="updates[0].length">
<div v-for="notice, index in updates[0]" class="col-md-3 col-6 my-1">
<!--Qua metto le carte-->
<div class="card">
<div class="card-body">
<h4 class="card-title">[[notice.titolo]]</h4>
<p><a v-bind:href="'notices/'+ notice.id" tabindex=0>Vedi dettaglio</a></p>
<button class="btn btn-primary" @click="hide(notice)" tabindex=0>Nascondi</button>
</div>
</div>
</div>
</div>
<div class="row" v-else>
Nessun nuovo avviso oggi
</div>
</div>
<br>
The problem is that when I firstly log in to the page the console log shows:
TypeError: updates[0] is undefined
I think to know the reason why this happens: when I log in the Vue instance calls the this.getUpdates() function but, since it’s an asynchronous call, it renders the HTML whiteout waiting for the response, and therefore the updates[0] , in the first evaluation, is empty.
Is there a solution for this issue? Thank you.
Solution
Your guess is correct. There is no way to ‘pause’ the execution inside the lifecycle hooks. The best practice is to load your components with a loading state and then trigger a flag (or use a watcher property) to update the components once the data is loaded.
A simple way to solve this issue would be to wrap it inside a conditional div that checks if updates
is defined yet:
<div v-if="updates && updates.length>0">
<div class="row" v-if="updates[0].length">
<div v-for="notice, index in updates[0]" class="col-md-3 col-6 my-1">
<!--Qua metto le carte-->
<div class="card">
<div class="card-body">
<h4 class="card-title">[[notice.titolo]]</h4>
<p><a v-bind:href="'notices/'+ notice.id" tabindex=0>Vedi dettaglio</a></p>
<button class="btn btn-primary" @click="hide(notice)" tabindex=0>Nascondi</button>
</div>
</div>
</div>
</div>
<div class="row" v-else>
Nessun nuovo avviso oggi
</div>
</div>
Eventually though, you should implement a loading state to let user know that some data is being fetched in the background.
I don’t have much experience with Django routing, and how it couples with Vue, but in Vue-router, and generally speaking, if your component depends completely upon the data being fetched, you do it before the navigation is accepted, and then pass it onto the components. For anyone else using Vue-router, here’s a link on how to do that.
Answered By – Mythos
This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0