Vue.js data: undefined - vue.js

I am new to Vue.js.
Please advice me.
I get comments: undefined so comments are not displaying.
xhr is normal with 200.
Thank you
Thank you
Thank you
Thank you
Thank you
<template>
<div>
<ul class="media-list">
<li class="media" v-for="comment in comments">
{{ $comment.body }}
</li>
</ul>
</div>
</template>
<script>
export default {
data () {
return {
comments: []
}
},
props: {
postid: null
},
methods: {
getComments () {
this.$http.get('/blog/' + this.postid + '/comments').then((response) => {
this.comments = response.json().data;
});
}
},
mounted () {
this.getComments();
}
}

Basically there are two problems:
$comment don't exist
You have no data on response.json().data, that's why you get a undefined
I used a different API just to test it (as I don't have access to yours).
TEMPLATE
<div id="app">
<ul class="media-list">
<li class="media" v-for="comment in comments">
{{ comment.familyName + ', ' + comment.givenName }}
</li>
</ul>
</div>
SCRIPT
new Vue({
el: '#app',
data () {
return {
comments: []
}
},
props: {
postid: null
},
methods: {
getComments () {
this.$http.get('//ergast.com/api/f1/drivers.json').then((response) => {
this.comments = response.body.MRData.DriverTable.Drivers;
});
}
},
mounted () {
this.getComments();
}
});
Check out a working example here

this.comments = response.json().data;
console.log(this.comments) ;
to see what you get ;
you define comments=Array ;
maybe you get the response.json().data is not a Array;

Try using vm instead of this. In API response make sure what you are getting using console.log(). If response is already in json do not use response.json(). In HTML change $comment.body to comment.body. Make sure you have the body key in comments[] array.
<template>
<div>
<ul class="media-list">
<li class="media" v-for="comment in comments">
{{ comment.body }}
</li>
</ul>
</div>
</template>
<script>
export default {
data () {
return {
comments: [],
postid: null
}
},
props: {
},
methods: {
getComments () {
let vm = this;
vm.$http.get('/blog/' + vm.postid +
'/comments').then((response) => {
console.log(response)
vm.comments = response.data;
});
}
},
mounted () {
let vm = this;
vm.getComments();
}
}
}

:
My suggestion is to properly use try-catch statements.
I have found this is the safest and proper way to manage cases where variable could take undefined or null values, instead of trying to "if" everything.
try {
val = localStorage.getItem('accesstoken')
} catch (error) {
alert(error)
}
Take care!

Related

Losing my data when i refresh page in vuejs

I'm creating a social network for project in my formation, i have a like system and it work.
i have a components cardArticle with all info and i try to do a like count. It work but when i refresh the page or going on other page, i lost all my data likes (my data is not saved)
components/CardArticle.vue
<template>
<div id="card">
<div>
<a class="cardLink">
<img class="card-img" v-if="post.imageUrl !== undefined" :src="post.imageUrl" />
<h2 class="cardTitle"> {{ post.title }}</h2>
<p class="cardDescription"> {{ post.description }}</p>
</a>
</div>
<div class="buttonIcon">
<div>
<button type="button" class="buttonDelete" id="buttonDelete" #click="deletePost"
v-if="this.post.userId === this.user.userId || this.user.isAdmin === true">Supprimer</button>
<button type="button" class="buttonEdit" id="buttonEdit" #click="modifyPost"
v-if="this.post.userId === this.user.userId || this.user.isAdmin === true">
Editer
</button>
</div>
<div class="divIconLike">
<div class="iconLike">
<a #click="sendLike">
<i class="fa-regular fa-thumbs-up"></i>
</a>
</div>
<div class="countLike">
<p> {{ likes }} </p>
</div>
</div>
</div>
</div>
</template>
<script>
import axios from "axios";
import router from "../router/index.js";
export default {
name: 'CardArticle',
data () {
return {
likes: 0
}
},
props: {
post: {
type: Object
}
},
computed: {
user() {
return this.$store.getters.user;
}
},
methods: {
sendLike() {
axios.post("http://localhost:3000/api/articles/" + this.post._id + "/like", {
userId: this.user.userId
}, {
headers: {
Authorization: "Bearer " + this.user.token
}
})
.then(response => this.likes = response.data.article.likes)
.catch(error => console.log(error))
}
}
}
</script>
views/home.vue
<template>
<div class="home" v-if="this.user.token !== null">
<CardArticle v-for="post in allPosts" v-bind:key="post.id" :post="post" />
</div>
</template>
<script>
import CardArticle from "../components/CardArticle.vue"
import axios from "axios";
export default {
name: 'HomeArticle',
data () {
return {
post: {
title: "",
description: "",
imageUrl: ""
},
allPosts: [],
}
},
computed: {
user() {
return this.$store.getters.user;
}
},
components: {
CardArticle,
},
mounted() {
axios.get("http://localhost:3000/api/articles", {
headers: {
Authorization: "Bearer " + this.user.token
}
})
.then(response => {
this.allPosts = response.data;
})
.catch(error => {
return error;
})
}
}
</script>
What i should do for not losing my data ?
I would not use vuex or localstorage for that if possible, you have idea ?
Thanks for your help
If you loading data from server, then refresh page, you always will be lose data, because browser loading page again from server, and application will load data again.
If you don't want use vuex (but why not?), you can write data to cookies (by setting cookie value), then load it on app startup (when page is loaded). But it's not best practice at all. You can use vue3-cookies lib (link).
By the way, better learn to use stores, most progressive, I think, is Pinia.
Check: https://pinia.vuejs.org/
i lost all my data likes (my data is not saved)
likes is belong to each articles and It should have been saved to your db and call API to retrieve it again on component mounting:
export default {
name: 'CardArticle',
data () {
return {
likes: 0 // It's not managed by component state
}
},
methods: {
sendLike() {
axios.post("http://localhost:3000/api/articles/" + this.post._id + "/like", {
userId: this.user.userId
}, {
headers: {
Authorization: "Bearer " + this.user.token
}
})
.then(
// invalidates, update allPosts props (emit to parent)
)
.catch(error => console.log(error))
}
}
}

Why Vue doesn't refresh list using props?

On my App, on mounted() method, I call an API, which give to me a JSON with a list of items; than, I update the prop I've set in my target Homepage component:
Homepage.pages = resJSON.data.pages;
Here's the App code:
<template>
<div id="app">
<Homepage title="PWA Test"/>
</div>
</template>
<script>
import Homepage from './components/Homepage.vue'
export default {
name: 'App',
components: {
Homepage
},
mounted() {
let endpoint = "http://localhost:5000/api/graphql?query={pages(orderBy:{contentItemId:asc}){contentItemId,createdUtc,author,displayText,description%20}}";
fetch(endpoint, {
method:'GET',
headers: {
'Accept':'application/json',
'Content-Type':'application/json'
}
})
.then((response) => {
// check for HTTP failure
if (!response.ok) {
throw new Error("HTTP status " + response.status);
}
// read and parse the JSON
return response.json();
})
.then((res) => {
Homepage.pages = res.data.pages;
})
.catch((error) => {
console.log(error);
});
}
}
</script>
<style>
</style>
Here's the Homepage component:
<template>
<div id="homepage">
<h1>{{ title }}</h1>
<ul>
<li v-for="page in pages" :key="page.description">#{{ page.description }}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Homepage',
props: {
title: String,
pages: []
}
}
</script>
<style scoped>
</style>
But the ul doesn't update after receiving the JSON and updating the props pages. Where's my error?
you need to get the response.json(); in a data property of the App and then pass it down to the Homepage component. So your code should you look like this,
App code:
<template>
<div id="app">
//binding page into data property
<Homepage title="PWA Test" :pages="pages"/>
</div>
</template>
<script>
import Homepage from './components/Homepage.vue'
export default {
name: 'App',
data: function () {
return {
//data propety
pages : []
}
},
components: {
Homepage
},
mounted() {
let endpoint = "http://localhost:5000/api/graphql?query={pages(orderBy:{contentItemId:asc}){contentItemId,createdUtc,author,displayText,description%20}}";
fetch(endpoint, {
method:'GET',
headers: {
'Accept':'application/json',
'Content-Type':'application/json'
}
})
.then((response) => {
if (!response.ok) {
throw new Error("HTTP status " + response.status);
}
// assign the result to the data property
this.page = response.json();
})
.then((res) => {
Homepage.pages = res.data.pages;
})
.catch((error) => {
console.log(error);
});
}
}
</script>
Do you pass the props in a template after this.pages = res.data.pages?
<Homepage :pages="pages" />
I think there are some mistakes that you have done in your code, if you want change update prop value then you have to initialized your props values in script.
<template>
<div id="homepage">
<h1>{{ title }}</h1>
<ul>
<li v-for="page in currentPages" :key="page.description">#{{ page.description }}
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Homepage',
props: {
title: String,
pages: []
}
data: function () {
return {
currentPages: this.pages
}
}
}
</script>
I hope this will help you to solve your issue- thanks!

VueJs + Firestore realtime listeners and update changes

I'am working with vuejs and firestore.I'am trynig to make my data change without refreshing page. the code below add me new line when i change the value on firestore.
value before changing:
value after changing:
my code:
{
<template>
<div id="dashboard">
<ul class="collection with-header">
<li class="collection-header"><h4>PLC</h4></li>
<li v-for="post in plc_value" v-bind:key="" class="collection-item">
<div class="chip">{{post.value_g}}</div>
<router-link class="secondary-content" v-bind:to="{ name: '', params:{} }"><i class="fa fa-eye"></i></router-link>
</li>
</ul>
</div>
</div>
</template>
<script>
import db from './firebaseInit';
export default {
name: 'dashboard',
data() {
return {
plc_value: [],
// loading: true
};
},
created() {
db
.collection('plc_value')
.onSnapshot(snap => {
snap.forEach(doc => {
const data = {
id: doc.id,
value_g: doc.data().value_g
};
this.plc_value.push(data);
});
});
}
};
</script>
}
In your created function, do this:
created() {
db
.collection('plc_value')
.onSnapshot(snapshot => {
const documents = snapshot.docs.map(doc => {
const data = {
id: doc.id,
value_g: doc.data()
}
return data
});
this.plc_value.push(documents);
});
});
}

VueJS: State from deleted component remains and affects the next one (sibling)

I have a notifications component that has some notifications item child components that are fed from an array in the parent component. The child component has the ability to update and delete itself. It can mark itself as read when clicked. It will make a request to the server with Axios and then change a button icon to close (fa-close). Which works fine. Now it can delete itself. When clicked it will send a delete request to the server, and when successful emit an event to the parent component to delete it from the array with splice. Now it works fine but the issue I'm having is that the new icon that I changed still remains for the next component (next item in the array). And that bugs me because I can't seem to find a way to make it display the initial icon which was initialize with the component. here's some code if that can help NotificationsItem.vue <template>
<li class="list-group-item list-group-item-info">
<button class="pull-right"
title="#lang('text.notifications.markAsRead')"
#click="markAsReadOrDestroy">
<i class="fa" :class="iconClass" v-show="!loading"></i>
<i class="fa fa-spinner fa-spin fa-lg fa-fw" v-show="loading"></i>
</button>
<!-- {{ notification.data }} -->
I'm the index {{ index}} and the ID is {{notification.id}}
<span class="hljs-tag"></<span class="hljs-name">li</span>></span>
</template>
<script>
export default {
props: ['notification', 'index'],
data() {
return {
loading: false,
icon: 'check',
markedAsRead: false,
}
},
computed: {
iconClass() {
return 'fa-' + this.icon;
}
},
methods: {
markAsReadOrDestroy() {
if (this.markedAsRead) {
this.destroy();
} else {
this.markAsRead();
}
},
markAsRead() {
let vm = this;
this.loading = true;
this.$http.patch('/notifications/markasread/' + this.notification.id)
.then(function(response) {
console.log(response);
vm.loading = false
vm.markedAsRead = true
vm.icon = 'close'
})
.catch(function(error) {
console.log(error);
vm.loading = false;
});
},
destroy() {
let vm = this;
this.loading = true;
this.$http.delete('/notifications/' + this.notification.id)
.then(function(response) {
console.log(response);
vm.loading = false;
vm.$emit('deleted', vm.index);
})
.catch(function(error) {
console.log(error);
vm.loading = false;
});
}
},
mounted() {
console.log('Notifications Item mounted.')
}
}
</script>
NotificationsList.vue <template>
<div class="list-group">
<notifications-item
v-for="(notification, index) in notifications"
:notification="notification"
#deleted="remove"
:index="index">
{{ notification.data['text'] }}
</notifications-item>
</div>
</template>
<script>
export default {
data() {
return {
notifications: notifications.data,
}
},
methods: {
remove(index) {
console.log(index);
this.notifications.splice(index, 1);
}
},
mounted() {
console.log('Notifications List mounted.')
}
}
</script>
If anyone can help me that would be greatly appreciated.
You need to pass index as paramter in remove function, like following:
<notifications-item
v-for="(notification, index) in notifications"
:notification="notification"
#deleted="remove(index)"
:index="index">
{{ notification.data['text'] }}
</notifications-item>
I found a fix by adding a key attribute on the child component with a unique value (the notification id). And that's it.

I am new to vue js ... can't display loaded data from a php file

Template part :
`<div class="col-sm-6" >
<ul class="list-group" id="pos">
<li class="list-group-item" v-for="(itm, index) in items">
<strong>{{index}} : {{ itm.sub }}</strong> - {{ itm.price }}
</li>
</ul>
</div>`
Script part :
new Vue({
el: '#pos',
http: {
root: '/vuetest',
headers: {
Authorization: 'Basic YXBpOnBhc3N3b3Jk'
}
},
data: {
items: []
},
created:function () {
this.$http.get('index.php').then(function(resp,status,request){
this.items = resp.data;
console.log(this.items); // got data but not displayed in browser
}.bind(this));
}
});
My Source files are from cdnjs.cloudeflare.com:
vue.js (2.1.4)
vue-resource.js (1.0.3).
Well, this isn't that...
created:function () {
this.$http.get('index.php').then(function(resp,status,request){
this.items = resp.data; // this is referring to the current function, and not to vue's scope.
console.log(this.items); // got data but not displayed in browser
}.bind(this));
}
So the correct use is:
created:function () {
var self = this
this.$http.get('index.php').then(function (resp,status,request) {
self.items = resp.data;
console.log(this.items);
});
}
As MU commented above, better you to use Arrows functions, so the "this" will have the scope you want.
mounted () {
}
Then you can access all your Data properties normally with "this".