Reputation: 1719
I've got a screen that has divided its main data sections into tabs, and hope to have each tab on its own component.
However, for some reason the data is not showing on the component when it first renders. The thing is, if you click the button to refresh the data it loads just fine. I'm getting no error messages either way, so I think I must be misinterpreting the VueJS lifecycle.
const CommentScreen = {
props: {
accountid: {
type: Number,
required: true
}
},
template: `
<div>
<CommentForm
v-on:commentsupdated="comments_get"
v-bind:accountid="accountid"
></CommentForm>
<v-btn round color="primary" v-on:click="comments_get" dark>Refresh Comments</v-btn>
<v-data-table
:headers="commentheaders"
:items="comments"
hide-actions>
<template slot="items" slot-scope="props">
<td>{{ props.item.entrydate }}</td>
<td>{{ props.item.entryuserforename + " " + props.item.entryusersurname }}</td>
<td>{{ props.item.comment }}</td>
</template>
</v-data-table>
</div>
`,
components: {
'CommentForm': CommentForm
},
data(){
return {
commentheaders:[
{ text:'Entry Date', value:'entrydate' },
{ text:'Entry User', value:'entryuserforename' },
{ text:'Comment', value:'comment' }
],
comments:[]
}
}
,
mounted() {
this.comments_get();
},
methods:{
comments_get(){
let url = new URL('/comments/', document.location);
url.searchParams.append('accountid',this.accountid);
let options = {
method: 'GET',
mode: 'cors',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json;charset=UTF-8'
}
};
self = this;
fetch(url, options)
.then(
response => {
if (response.status === 401) {
self.$root.$emit('notloggedin');
} else if (response.status === 403) {
self.$root.$emit('displayalert','Missing Permission: View Comments');
} else if (response.status === 204) {
self.comments = [];
} else if(!response.ok) {
response.json()
.then(data => self.$root.$emit('displayalert', data.errors))
.catch(error => self.$root.$emit('displayalert', error.status + ' ' + error.statusText));
} else {
response.json()
.then(data => self.comments = data.comments)
.catch(error => self.$root.$emit('displayalert', error));
}
}
)
.catch(error => self.$root.$emit('displayalert', error));
}
}
};
Forgive the amount of code dumped above, I'm not sure what I could/should remove to make the question more brief.
Can anyone please advise how I can have the data load automatically on this component when its first loaded?
Many thanks in advance.
Upvotes: 0
Views: 700
Reputation: 1719
I figured it out!
The issue with the code is in the below line:
self = this;
It was looking the wrong context the first time the code ran, and only the first time. Replacing it with
let self = this;
And the problems were fixed.
I hate computers at times, they always do what I say and not what I mean!
Upvotes: 0
Reputation: 8528
The mounted
hook is async
, which makes this kind of tricky.
Example of something similar to what you're trying to do..
new Vue({
el: "#app",
data: {
placeId: 1,
sight: "",
sightImages: [],
slideIndex: 1
},
mounted() {
var self = this;
fetch(`https://jsonplaceholder.typicode.com/albums/${this.placeId}/photos?_start=1&_end=10`)
.then(response => {
if (response.ok) {
return response;
} else {
if (response.status === 401) {
alert("401");
//self.$root.$emit("notloggedin");
}
if (response.status === 403) {
alert("403");
//self.$root.$emit("displayalert", "Missing Permission: View Comments");
}
if (response.status === 204) {
alert("204");
//self.comments = [];
}
}
})
.then(response => response.json())
.catch(error => {
console.log("ERROR " + error);
})
.then(data => {
self.sight = {
id: data[0].albumId
};
self.sightImages = data;
})
/** IF YOU REMOVE THIS THINGS WONT WORK RIGHT */
.then(() => {
self.showSlides(self.slideIndex);
});
/** */
},
methods: {
showSlides(n) {
let i;
let slides = document.getElementsByClassName("mySlides");
let dots = document.getElementsByClassName("demo");
let captionText = document.getElementById("caption");
if (n > slides.length) {
this.slideIndex = 1;
}
if (n < 1) {
this.slideIndex = slides.length;
}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" active", "");
}
console.log(slides[0]);
console.log(document.getElementsByClassName("mySlides").length);
slides[this.slideIndex - 1].style.display = "block";
dots[this.slideIndex - 1].className += " active";
captionText.innerHTML = dots[this.slideIndex - 1].alt;
},
plusSlides(n) {
this.showSlides((this.slideIndex += n));
},
currentSlide(n) {
this.showSlides((this.slideIndex = n));
}
},
});
.demo-cursor {
width: 3% !important;
cursor: pointer;
margin: 0px 2px
}
.sight-photos {
width: 6%;
}
.row {
display: inline-block;
}
.cntrlbtn {
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
<div id="app">
<div class="wrapper">
<div class="sight-container">
<p class='sight-name'>Sight Id: {{ sight.id }}</p>
<div class="photos-container">
<div v-for='(image, index) in sightImages' class="mySlides">
<div class="numbertext">{{ index + 1 }} / {{ sightImages.length }}</div>
<img class='sight-photos' :src="image.thumbnailUrl">
</div>
<a class="cntrlbtn" @click='plusSlides(-1)'>❮</a>
<a class="cntrlbtn" @click='plusSlides(1)'>❯</a>
<div class="caption-container">
<p id="caption"></p>
</div>
<div class="row">
<img v-for='(image, index) in sightImages' class="demo-cursor" :src="image.url" @click="currentSlide(index + 1)">
</div>
</div>
</div>
</div>
</div>
You could try something like this:
const self = this;
fetch(url, options)
.then(response => {
if (response.ok) {
return response;
} else {
if (response.status === 401) {
self.$root.$emit("notloggedin");
}
if (response.status === 403) {
self.$root.$emit("displayalert", "Missing Permission: View Comments");
}
if (response.status === 204) {
self.comments = [];
}
}
})
.then(response => response.json())
.catch(error => {
self.$root.$emit("displayalert", error);
})
.then(data => {
self.comments = data.comments;
});
Upvotes: 1