How to display values of an associative array with vue.js? - javascript

I have an array which is:
And I want to make a foreach loop and list all key's & script_content's to the view.
My vue components mounted method:
mounted() {
this.loading = true;
axios.get('/app/json-ld/json-ld-settings')
.then(res => {
let data = res.data;
console.log(data.scripts);
this.key = data.scripts[0]['key'];
this.scriptContent = data.scripts[0]['script_content'];
})
.catch(error => {
this.loading = false;
this.$notify({
group: 'notify',
type: 'error',
text: 'Something happened! Please refresh the page and try again or contact support!',
});
});
},
component data:
data: () => ({
errors: {},
key: [],
scriptContent: [],
I am able to display the values of the first array, but don't know how to make a foreach loop in an associative array.
HTML:
<div class="py-3 d-flex flex-row justify-content-end align-content-end">
<div class="pr-2">
<h5>Key</h5>
<span>{{key}}</span>
</div>
<div class="pl-2">
<h5>Script content</h5>
<span>{{scriptContent}}</span>
</div>
</div>
The goal is to list all key's and script_content's in a HTML list or a div.
Any help will be appriciated.

You can just use codes below:
data() {
return {
keys: [],
contents: [],
}
}
...
for (let index in data) {
this.keys.push(data[index].key);
this.contents.push(data[index].script_content);
}
...
Then you can use v-for in html codes to use keys and contents.

You should store all scripts into the data, not just data.scripts[0], and then iterate over them in the template using v-for directive. Here is a couple of good examples:
https://v2.vuejs.org/v2/guide/list.html

Related

Vue js vuex unable to display my data in my loop

but i can't show the comments with v-for and i don't understand why my comment data is not working.
I know there is an error but I can't find it.
My request returns a data , but i can't display it my loop.
Thanks for your help
In store/index.js
state :{
dataComments:[]
}
mutation: {
getComments(state, dataComments) {
console.log(dataComments)
state.dataComments = dataComments;
},
}
action: {
getArticleComments: ({ commit }, dataArticles) => {
return new Promise(() => {
instance.get(`/comment/${dataArticles.article_id}`)
.then(function () {
commit('getComments');
})
.catch(function (error) {
console.log(error)
})
})
},
}
in my views/home.vue
export default {
name: "Home",
data: function () {
return {
articles: [],
comments: [],
}
},
methods: {
getArticleComments(comment) {
this.$store
.dispatch("getArticleComments",comment)
.then((res) => {
this.comments = res.data;
});
},
}
<div class="pos-add">
<button
#click="getArticleComments(article)"
type="button"
class="btn btn-link btn-sm">
Show comments
</button>
</div>
<!-- <div v-show="article.comments" class="container_comment"> -->
<div class="container_comment">
<ul class="list-group list-group comments">
<li
class="
list-group-item
fst-italic
list-group-item-action
comment
"
v-for="(comment, indexComment) in comments"
:key="indexComment"
>
{{ comment.comment_message }}
<!-- {{ comment.comment_message }} -->
</li>
</ul>
</div>
Your action getArticleComments does not return anything and I would avoid changing the action to return data. Instead remove the assignment to this.comments in home.vue
Actions do not return data, they get data, and call mutations that update your store.
Your store should have a getter that exposes the state, in this case the dataComments.
getters: {
dataComments (state) {
return state.dataComments;
}
}
Then in your home.vue you can use the helper mapGetters
computed: {
...mapGetters([
'dataComments'
])
}
You want your views to reference your getters in your store, then when any action updates them, they can be reactive.
More here: https://vuex.vuejs.org/guide/getters.html
As far as I see, you don't return any data in your getArticleComments action. To receive the comments you should return them, or even better, get them from your store data directly.
First make sure that you pass the response data to your mutation method:
getArticleComments: ({ commit }, dataArticles) => {
return new Promise(() => {
instance.get(`/comment/${dataArticles.article_id}`)
.then(function (res) {
commit('getComments', res.data);
})
.catch(function (error) {
console.log(error)
})
})
},
After dispatching you could either return the response data directly or you could access your store state directly. Best practice would be working with getters, which you should check in the vue docs.
getArticleComments(comment) {
this.$store
.dispatch("getArticleComments",comment)
.then((res) => {
// in your case there is no res, because you do not return anything
this.comments =
this.$store.state.dataComments;
});
},

Display Vue Computed Array of Objects in HTML

I am having trouble displaying an array of objects from Vue that is fetched from an express server using fetch(); The fetching of the data works but I am not sure as how to display it in html. Below is the Vue code that is successfully fetching the JSON from Express.
computed: {
async fetchData() {
fetch('http://localhost:4000/lessons').then(
function (response) {
response.json().then(
function (json) {
this.lessons = json;
console.log(this.lessons)
});
})
},
}
The console.log successfully displays the fetched array of objects but it is not being displayed in HTML. Below is the HTML code that is not displaying the fetched array of objects.
<div v-for="lesson in fetchData" class="card">
<h2 v-text ="lesson.subject"></h2>
<figure>
<img v-bind:src="lesson.image">
</figure>
<p>Location: {{lesson.location}}</p>
<p>Price: £{{lesson.price}}</p>
<p>Description: {{lesson.description}}</p>
<p>Maximum Class Size: {{lesson.maximumSpaces}} People</p>
</div>
How will I be able to display the array of objects in the HTML file? Thanks for your time.
There are a few problems: 1) Computeds are not async. 2) The template is not async, so you could not call even an async method that way. 3) Your fetch callback function should be an arrow function or it injects its own this and blocks the data setting. 4) Use a :key with v-for. Here is a proper pattern, use a method to fetch the data:
methods: {
async fetchData() {
const response = await fetch('http://localhost:4000/lessons');
this.lessons = await response.json();
}
}
You can call it in the created or mounted lifecycle hook, or somewhere else:
data: () => ({
lessons: []
}),
created() {
this.fetchData()
}
Then iterate over the data:
<div v-for="(lesson, index) in lessons" class="card" :key="index">
...
</div>
Here is a demo:
new Vue({
el: "#app",
data: () => ({
lessons: []
}),
created() {
this.fetchData()
},
methods: {
async fetchData() {
const response = await fetch('https://jsonplaceholder.typicode.com/todos');
this.lessons = await response.json();
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(lesson, index) in lessons" :key="index">
{{ lesson }}
</div>
</div>

VueJS Array Index returns wrong result

I am creating a poetry app where poetry is fetched using an API call.
I fetch data using axios library and do v-for to populate data. I use the index from v-for to populate the image for each poem respectively.
I display 10 results per page using my own custom pagination. Currently, it's only for next button though.
The problem I am facing is when I navigate to Page 2! As I said earlier, that I use v-for's index to display images, it doesn't actually update the index when I move to the next page. As a result, the images are shown same as of page 1.
Code:
new Vue({
el: '#app',
data: {
proxy: 'https://cors-anywhere.herokuapp.com/',
imageIndex: 0,
pagination: {
start: 0,
end: 10,
resPerPage: 10
},
fetchData: [],
fetchImages: []
},
methods: {
paginate() {
this.pagination.start = this.pagination.start + this.pagination.resPerPage;
this.pagination.end = this.pagination.end + this.pagination.resPerPage;
},
async fetchDatas() {
try {
const res = await axios(`${this.proxy}http://poetrydb.org/author,title/Shakespeare;Sonnet`);
if (res) {
this.fetchData = res.data;
}
} catch (error) {
console.log(error);
}
},
async fetchImagess() {
const key = '9520054-7cf775cfe7a0d903224a0f896';
const perPage = 154;
const proxy = ''
const res = await axios(`${this.proxy}https://pixabay.com/api/?key=${key}&per_page=${perPage}`);
this.fetchImages = res.data.hits;
}
},
mounted() {
this.fetchDatas();
this.fetchImagess();
}
});
<div id="app">
<div v-for="(poetry, index) in fetchData.slice(this.pagination.start, this.pagination.end)">
<div>
<img :src="fetchImages[index].largeImageURL.toLowerCase()" style="max-width: 100%;height: auto;max-height: 320px;">
<div>
<h5>{{ poetry.title }}</h5>
<span v-for="(poetryBody, i) in poetry.lines.slice(0, 5)">
{{ i === 4 ? poetryBody.split(',').join('') + '...' : poetryBody }}
</span>
<br>
Read More
</div>
</div>
</div>
<nav style="padding-top: 3em;">
<button #click="paginate()">Next</button>
</nav>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
JSFiddle: http://jsfiddle.net/sanjaybanjade/vnu654gk/9/
As you can see the images doesn't get updated when I goto Page 2! Please help me fix this!
And please ignore the console errors. I am gonna fix them later.
The quick fix would be to calculate the offset in line 4 to update on pagination:
<img v-bind:src="fetchImages[index + pagination.start].largeImageURL.toLowerCase()" style="max-width: 100%;height: auto;max-height: 320px;">
wrong at this line fetchImages[index].largeImageURL.toLowerCase().
Since you are iterating a sliced array of fetchData, it's index is related to sliced array, not original array. So, you should apply pagination slice to your fetchImages too.
When you run fetchData.slice(), it returns a new object. So if you slice out 10 new pieces of poetry, their indexes are still going to be 0-9, since the returned object only has that many items each time.
Why it's not working is because you only slice fetchData on this line fetchData.slice(this.pagination.start, this.pagination.end) but you don't slice the fetchImages what means fetchImages still is the same array it didn't change, meaning that index 0 is still the same image. Best is if you keep them in sync so I would add a pageData and pageImages array's and every time you change the paging you update both of them. like in a updatePageData method
new Vue ({
el: '#app',
data: {
proxy: 'https://cors-anywhere.herokuapp.com/',
imageIndex: 0,
pagination: {
start: 0,
end: 10,
resPerPage: 10
},
fetchData: [],
fetchImages: [],
pageData: [],
pageImages: []
},
methods: {
paginateNext() {
this.pagination.start = this.pagination.start + this.pagination.resPerPage;
this.pagination.end = this.pagination.end + this.pagination.resPerPage;
this.updatePageData()
},
updatePageData () {
this.pageData = this.fetchData.slice(this.pagination.start, this.pagination.end)
this.pageImages = this.fetchImages.slice(this.pagination.start, this.pagination.end)
},
async fetchDatas() {
try {
const res = await axios(`${this.proxy}http://poetrydb.org/author,title/Shakespeare;Sonnet`);
if(res) {
this.fetchData = res.data;
}
} catch(error) {
console.log(error);
}
},
async fetchImagess() {
const key = '9520054-7cf775cfe7a0d903224a0f896';
const perPage = 154;
const proxy = ''
const res = await axios(`${this.proxy}https://pixabay.com/api/?key=${key}&per_page=${perPage}`);
this.fetchImages = res.data.hits;
}
},
mounted() {
Promise.all([
this.fetchDatas(),
this.fetchImagess()
])
.then(() => this.updatePageData())
}
});
<div id="app">
<div v-for="(poetry, index) in pageData">
<div>
<img :src="pageImages[index].largeImageURL.toLowerCase()" style="max-width: 100%;height: auto;max-height: 320px;">
<div>
<h5>{{ poetry.title }}</h5>
<span v-for="(poetryBody, i) in poetry.lines.slice(0, 5)">
{{ i === 4 ? poetryBody.split(',').join('') + '...' : poetryBody }}
</span>
<br>
Read More
</div>
</div>
</div>
<nav style="padding-top: 3em;">
<button #click="paginateNext()">Next</button>
</nav>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>

Vuejs searchbar filter returns no result

Today I started playing around with VUEjs for the first time, so I tried to get data out from an URL with JSON. This worked perfectly fine, but I wanted more by adding a search bar. I've watched some tutorials online and I did the same as they did, but it didn't worked out very well for me. After adding filter() to my code I couldn't see anything on my screen. I'm now stuck and don't know what I did wrong in my code.
If I write for example "Bitcoin", I want to get the symbol, name and price back.
<div id="app">
<input type="text" v-model="search" placeholder="search coin">
<ul>
<li v-for="coin in filteredCoins">
{{ coin.symbol }} {{ coin.name }} {{ coin.quotes['USD']['price']}}
</li>
</ul>
</div>
<script src="https://unpkg.com/vue"></script>
<script>
const app = new Vue({
el: '#app',
data: {
data: [],
search: ''
},
computed: {
filteredCoins: function() {
return this.data.filter((coin) => {
return coin.title.match(this.search);
});
}
},
created () {
fetch('https://api.coinmarketcap.com/v2/ticker/')
.then(response => response.json())
.then(json => {
this.data = json.data
})
}
})
</script>
Codepen
json.data is an object, not an array, so you can't use filter on it. You'd need to translate that object to an array to filter it. You can do something like what Bert suggests in his codepen.
computed: {
filteredCoins () {
return Object.values(this.data).filter(coin => coin.name.toLowerCase().match(this.search.toLowerCase()))
},
},

Vuejs set method return to template

I'm new to Vue and I'm stuck at the moment. For the practice I'm making an app for episode checklist for series. The first part of the app searches series and add one of them to a database. Result for the search gives me a result like this: https://i.stack.imgur.com/QuOfc.png
Heres my code with template and script:
<template>
<div class="series">
<ul>
<li v-for="item in series" :key="item.id">
<img :src="image_url+item.poster_path"/>
<div class="info">
{{item.name}}
<br/>
<h5>{{item.id}}</h5>
Start Date: {{item.first_air_date}}
<br/>
{{getEpisodeNumber(item.id)}}
<br/>
{{getSeasonNumber(item.id)}}
</div>
</li>
</ul>
</div>
</template>
<script>
export default {
name: "series",
props: ["series"],
data() {
return {
image_url: "https://image.tmdb.org/t/p/w500",
api_key: {-api key-},
episode_url: "https://api.themoviedb.org/3/tv/",
}
},
methods: {
async getEpisodeNumber(showID) {
const json = await fetch(this.episode_url + showID + this.api_key)
.then((res) => { return res.json() })
.then((res) => { return res.number_of_episodes })
return await json
},
async getSeasonNumber(showID) {
const json = await fetch(this.episode_url + showID + this.api_key)
.then((res) => { return res.json() })
.then((res) => { return res.number_of_seasons })
return await json;
}
},
}
</script>
Methods should return to me a number but they return an object, probably promise object. But when I try to console.log the data in the methods they print a value(int). I need reach this value but I'm stuck. I tried to sort of thinks but it fails every time.
I just create a new component called show and pass item.id to this component. In show component, I use another fetch() to get show data again and now it works like I want.

Categories

Resources