Reputation: 41
I have an error on VueJS with a filter added in a v-for from an Axios response and doesn't understand how to solve it. The filter set_marked return a undefined value if i made a console.log on the value variable.
Here's the HTML:
<main id="app">
<div v-for="item in productList" :key="item.id">
<header>
<h2>{{ item.title }}</h2>
</header>
<article class="product-card">
{{ item.content | set_marked }}
</article>
</div>
</main>
And the Javascript:
var app = new Vue({
el: '#app',
data: {
loading: false,
loaded: false,
productList: []
},
created: function() {
this.loading = true;
this.getPostsViaREST();
},
filters: {
set_marked: function(value) {
return marked(value);
}
},
methods: {
getPostsViaREST: function() {
axios.get("https://cdn.contentful.com/spaces/itrxz5hv6y21/environments/master/entries/1Lv0RTu6v60uwu0w2g2ggM?access_token=a2db6d0bc4221793fc97ff393e541f39db5a65002beef0061adc607ae959abde")
.then(response => {
this.productList = response.data;
});
}
}
})
You can also try it on my codepen: https://codepen.io/bhenbe/pen/deYRpg/
Thank you for your help !
Upvotes: 1
Views: 1917
Reputation: 3750
Usually I just create a method when I need filtering and then use it when needed in my component.
ie:
methods: {
getPostsViaREST: function() {
axios.get("https://cdn.contentful.com/spaces/itrxz5hv6y21/environments/master/entries/1Lv0RTu6v60uwu0w2g2ggM?access_token=a2db6d0bc4221793fc97ff393e541f39db5a65002beef0061adc607ae959abde")
.then(response => {
this.productList = response.data;
});
},
filterPost(post) {
return _.toUpper(post);
}
}
And then in your component:
<h1>{{ filterPost(item.title) }}</h1>
Find here the full example:
https://codepen.io/Venomzzz/pen/mLrQVm?editors=1011
Upvotes: 0
Reputation: 2539
You are iterating with v-for
on productList
, but in your code productList
is not an array but an object (a dictionary in other words). In fact if you look at it, it has this structure:
{
"sys": {
"space": {
"sys": {
"type": "Link",
"linkType": "Space",
"id": "itrxz5hv6y21"
}
},
"id": "1Lv0RTu6v60uwu0w2g2ggM",
"type": "Entry",
"createdAt": "2017-01-22T18:24:49.677Z",
"updatedAt": "2017-01-22T18:24:49.677Z",
"environment": {
"sys": {
"id": "master",
"type": "Link",
"linkType": "Environment"
}
},
"revision": 1,
"contentType": {
"sys": {
"type": "Link",
"linkType": "ContentType",
"id": "page"
}
},
"locale": "fr-BE"
},
"fields": {
"title": "Retour sur douze années de design",
"content": "Douze années ... vie."
}
}
Iterating through it, on the first iteration will assign to item
the value of the "sys"
key, which is:
{
"space": {
"sys": {
"type": "Link",
"linkType": "Space",
"id": "itrxz5hv6y21"
}
},
"id": "1Lv0RTu6v60uwu0w2g2ggM",
"type": "Entry",
...
"locale": "fr-BE"
},
and on the second iteration the value of the "fields"
key, which has the value:
{
"title": "Retour sur douze années de design",
"content": "Douze années ... vie."
}
Since you are accessing item.title
and item.content
, and title
and content
keys are not present in the first object, but only in the second, in the first iteration they will be undefined
. So, in the first iteration you are passing undefined
as the value of item.content
to the set_marked
filter.
productList
is the response to the GET
request, which as we have seen is not returning an array but an object.
If you add to the filter the check if (!value) return '';
it will work, but you are just hiding the problem of the discrepancy between what the API returns and what you are expecting.
If you build productList
as an array by filtering through the sub-objects of result.data
and keeping only those containing title
and contents
fields, it works:
function marked(value) {
return value.toUpperCase();
}
var app = new Vue({
el: '#app',
data: {
productList: []
},
created: function() {
this.loading = true;
this.getPostsViaREST();
},
filters: {
set_marked: function(value) {
// console.log(value);
return marked(value);
}
},
methods: {
getPostsViaREST: function() {
axios.get("https://cdn.contentful.com/spaces/itrxz5hv6y21/environments/master/entries/1Lv0RTu6v60uwu0w2g2ggM?access_token=a2db6d0bc4221793fc97ff393e541f39db5a65002beef0061adc607ae959abde")
.then(response => {
// this.productList = response.data;
let data = response.data;
let productList = [], key;
for (key in data) {
let val = data[key];
if ((val.title !== undefined) && (val.content !== undefined)) {
productList.push(val);
}
}
this.productList = productList;
});
}
}
})
@import url('https://fonts.googleapis.com/css?family=Lato');
body{
font-family: 'Lato', sans-serif;
font-size: 1.125rem;
}
#app > div{
max-width: 68ch;
margin: 0 auto;
}
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<main id="app">
<div v-for="item in productList" :key="item.id">
<header>
<h1>{{ item.title }}</h1>
</header>
<article class="product-card" v-html="$options.filters.set_marked(item.content)"></article>
</div>
</main>
Upvotes: 1
Reputation: 41
Ok, i find in the documentation the solution.
I must add the following code to the filter set_marked to work properly:
if (!value) return '';
value = value.toString();
I currently don't know why this additional lines are required.
I had a second problem because the returned html is escaped by VueJS. The easiest way to avoid this issue is to used the v-html directive. To apply a filter in the v-html directive, you must use this syntax :
v-html="$options.filters.set_marked(item.content)"
You can find my pen here : https://codepen.io/bhenbe/pen/deYRpg
Upvotes: 0