Cannot display data from an API using v-for in vuejs - api

I cannot get or display data from an API but the API is working fine and when I click the button, the data appears,
I want it to appear automatically
I'm using Axios method to connect to my API
I'm new to Vue.js and this is my simple code
var Ve = new Vue({
el: "#app",
data: {
products: [],
},
methods: {
getData: function(){
axios.get('http://localhost:8000/api/products')
.then(data => this.products = data.data)
.catch(err => console.log(err));
}
},
})
THIS IS WHERE I WANT TO DISPLAY MY DATA
<div class="col-sm-9 padding-right" id="app" >
<div class="features_items"><!--features_items-->
<h2 class="title text-center">المنتجات</h2>
<div class="col-sm-4" v-for="item in products">
<div class="product-image-wrapper">
<div class="single-products">
<div class="productinfo text-center">
<img src="images/products/2.jpeg" alt="" />
<h2>${{ item.price }}</h2>
<p>{{ item.name }}</p>
<i class="fa fa-shopping-cart"></i>أضف إلى السلة
</div>
<div class="product-overlay">
<div class="overlay-content">
<h2>${{ item.price }}</h2>
<p>{{ item.name }}</p>
<i class="fa fa-shopping-cart"></i>أضف إلى السلة
</div>
</div>
</div>
<div class="choose">
<ul class="nav nav-pills nav-justified">
<li><i class="fa fa-plus-square"></i>أضف إلى المفضلة</li>
</ul>
</div>
</div>
</div>
</div><!--features_items-->
<button type="button" #click="getData()">show</button>
</div>

I want it to appear automatically I'm using Axios method to connect to my API
As per my understanding, You want to bind the API data on component load. If Yes, You can call getData() method in the mounted() life cycle hook.
mounted hook used to run code after the component has finished the initial rendering and created the DOM nodes.
Demo :
var vm = new Vue({
el:"#app",
data: {
products: [],
},
mounted() {
this.getData();
},
methods: {
getData() {
// Here make an API call and bind the response in products.
this.products = [{
name: 'product1',
price: 50
}, {
name: 'product2',
price: 100
}, {
name: 'product3',
price: 150
}, {
name: 'product4',
price: 200
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul>
<li v-for="(item, index) in products" :key="index">{{ item.name }} - {{ item.price }}</li>
</ul>
</div>

Related

Any way to show a selected number of list items without having to add a conditional to each?

So let's say I have a list.
<div>
<ul>
<li>Item1</li>
<li>Item2</li>
<li>Item3</li>
</ul>
</div>
I only want every item after Item1 to be visible once a user clicks a button.
I could do this easily by creating a boolean called showItem, set it to false and then create a click event that sets it to true in a method.
<div #click="showItemBtn">
<ul>
<li>Item1</li>
<li v-if="showItem">Item2</li>
<li v-if="showItem">Item3</li>
</ul>
</div>
method: {
showItemBtn() {
this.showItem = true
}
}
But is there a more clean way of doing this, so I don't have to add a v-if statement to every single item that comes after Item1?
I'd add a v-for logic to the items with a reactive bool value with adding the click logic in the template. Here You don't need to have the click methoh in the Vue logic.
new Vue({
el: "#app",
data: {
showItem: false,
// You can add your list items here
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div #click="showItem = true">
<ul>
<li>Item1</li>
<li v-for="index in 3" v-if="showItem">Item{{ index + 1 }}</li>
</ul>
</div>
</div>
You can use v-for for your items:
new Vue({
el: "#demo",
data() {
return {
items: ['Item1', 'Item2', 'Item3'],
showItem: false
}
},
methods: {
showItemBtn() {
this.showItem = true
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div #click="showItemBtn">
<ul>
<li>Item</li>
<div v-for="item in items">
<li v-if="showItem">{{ item }}</li>
</div>
</ul>
</div>
</div>
Wrap the elements into the <template> element and use the v-if directive to the <template> only once.
new Vue({
el: "#app",
data() {
return {
showItem: false,
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div #click="showItem = !showItem">
<ul>
<li>Item1</li>
<template v-if="showItem">
<li>Item2</li>
<li>Item3</li>
</template>
</ul>
</div>
</div>
If looping is possible you can try the below way as well. I used the key as a unique id for demonstration, you can use anything which is unique.
new Vue({
el: "#demo",
data() {
return {
items: ['Item1', 'Item2', 'Item3'],
showItem: false
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div #click="showItem = !showItem">
<ul>
<template v-for="(item,index) in items">
<!-- If first item show direct otherwise check condition -->
<li :key="index" v-if="index == 0 || showItem">
{{ item }}
</li>
</template>
</ul>
</div>
</div>

Cannot read property 'forEach' of undefined VueJS Firebase

I use the framework VueJS and the NoSQL Database Firebase.
Here I want to display the products' data. And particulary the images of the products stored in the Cloud Firestore in Firebase.
This is the HTML code :
<div class="col-md-4"v-for="(product, index) in products" :key="index">
<div class="card product-item">
<carousel :perPage="1">
<slide v-for="(image, index) in product.images" :key="index">
<img :src="image" class="card-img-top" alt="..." width="250px">
</slide>
</carousel>
<div class="card-body">
<div class="d-flex justify-content-between">
<h5 class="card-title">{{ product.name }}</h5>
<h5 class="card-prices">{{ product.price }} €</h5>
</div>
<button class="btn btn-primary mx-3 butn" >
Add to cart
</button>
</div>
</div>
</div>
and the js script :
<script>
import {db} from '../../firebase';
export default {
name: "Productslist",
props: {
msg: String
},
data(){
return {
products: [],
}
},
firestore() {
return {
products: db.collection("products")
}
}
},
};
</script>
It displays the products data like the name and the price but not the images. I have a Cannot read property 'forEach' of undefined.
Probably one of the products have images set to undefined
product.images = undefined

vuex unknown action type: addToCart

hello everyone im trying to add product into cart array so i can render it after , i used vuex but i got this error : Console was cleared
[vuex] unknown action type: addToCart
hopefully u can give me some hint so i can fix this issue
thank you so much !!
here is the sandbox : https://codesandbox.io/s/suspicious-minsky-9cig7?file=/src/components/Products.vue
<template>
<main>
<div class="margin"></div>
<div class="shopTitle">
<h1>Shop</h1>
</div>
<section class="categoriesSection">
<ul class="categories">
<li>
See All
</li>
<li>
Shoes
</li>
<li>
Suits
</li>
</ul>
</section>
<section>
<div class="products">
<div class="product" v-for="product in filteredProducts" :key="product.productId">
<div class="imgproduct"></div>
<div class="productDetails">
<div>
<h1>{{product.productTitle}}</h1>
</div>
<div>
<i onClickButton class="fa fa-heart"></i>
</div>
<div>
<p>{{product.productPrice}}</p>
</div>
<div>
<i onClickButton #click="addToCart(product)" class="fa fa-shopping-cart"></i>
</div>
</div>
</div>
</div>
</section>
</main>
</template>
<script>
export default {
data() {
return {};
},
computed: {
selectedCategory: {
// getter
get: function() {
return this.$store.getters.selectedCategory;
},
// setter
set: function(newValue) {
return this.$store.commit("updateCategory", newValue);
}
},
filteredProducts() {
return this.$store.getters.filteredProducts;
}
},
methods: {
addToCart: function(product) {
this.$store.dispatch("addToCart", product);
}
}
};
</script>
You have a mutation called addToCart but no action either create an action called addToCart or just call the mutation directly :
this.$store.commit("addToCart", product);

Framework7 Loop Dynamic Content within Route

I am using Framework 7 to load demo cards in the router. The problem is I am not sure how to loop through multiple records in the template display.
Here is my route
{
path: '/about/',
async: function (routeTo, routeFrom, resolve, reject) {
// Requested route
// Get external data and return template7 template
app.request.json('data.json', function (data) {
console.log(data);
resolve(
// How and what to load: template
{
template: `<div class="page">
<div class="navbar">
<div class="navbar-inner sliding">
<div class="left">
<a href="#" class="link back">
<i class="icon icon-back"></i>
<span class="ios-only">Back</span>
</a>
</div>
<div class="title">News</div>
</div>
</div>
<div class="page-content">
<div class="card demo-card-header-pic">
<div style="background-image:url({{TitleImg}})" class="card-header align-items-flex-end"></div>
<div class="card-content card-content-padding">
<p class="date">{{Title}}</p>
<p>{{Header}}</p>
</div>
<div class="card-footer">Read more</div>
</div>
</div>
</div>`
},
// Custom template context
{
context: {
ID: data.content.ID,
Title: data.content.Title,
Header: data.content.Header,
Description: data.content.Description,
TitleImg: data.content.TitleImg,
},
}
);
});
}
},
here is sample json:
{
"contentType": "news",
"content": [{
"ID": 1,
"Title": "Test",
"Header": "Short Text",
"Description": "lorem ipsum",
"TitleImg": "/img/collab.jpg"
}, {
"ID": 2,
"Title": "Test2",
"Header": "Short Text2",
"Description": "lorem ipsum2",
"TitleImg": "/img/collab.jpg"
}]
}
Right now it doesn't show anything but I would like to see both entries.
TAKE 2 but still not working.... the items array has my data but the for loop doesnt work
{
path: '/about/',
async: function (routeTo, routeFrom, resolve, reject) {
// Requested route
// Get external data and return template7 template
app.request.json('data.json', function (data) {
for (var i = 0; i < data.content.length; i++) {
items.push({
ID: data.content[i].ID,
TitleImg: data.content[i].TitleImg,
Title: data.content[i].Title,
Header: data.content[i].Header
});
}
console.log(items);
resolve(
{
template: `<div class="page">
<div class="navbar">
<div class="navbar-inner sliding">
<div class="left">
<a href="#" class="link back">
<i class="icon icon-back"></i>
<span class="ios-only">Back</span>
</a>
</div>
<div class="title">News</div>
</div>
</div>
<div class="page-content">
<div class="card demo-card-header-pic" v-for="item in items">
<div style="background-image:url({{TitleImg}})" class="card-header align-items-flex-end"></div>
<div class="card-content card-content-padding">
<p class="date">{{Title}}</p>
<p>{{Header}}</p>
</div>
<div class="card-footer">Read more</div>
</div>
</div>
</div>`
},
{
items: items,
}
);
});
}
},
EDIT - Working solution thanks #djiggy
{{#each items}}
<div class="card demo-card-header-pic">
<a href="/about/{{ID}}/">
<div style="background-image:url({{TitleImg}})" class="card-header align-items-flex-end"><div class="card-headerTxt">{{Title}}</div></div>
<div class="card-content card-content-padding">
<p>{{Header}}</p>
</div>
</a>
</div>
{{/each}}
When you use data as Template7, you have to use Template7 syntax (cf. expressions syntax section)
So in your case, you have to update v-for to each block
Useful link : Access to object with each

Programmatically append existing component to existing v-model in VueJS

Like the title says, Im trying to append a vue-component to an existing v-model
The only thing i found on the internet was the v-for solution to add more elements, but that is not what I want to do since this v-model could have multiple components
chat.vue
The V-model im trying to append to
<template>
<ul class="chat-ul" v-model="messages">
<chat-entry :name="name" :message="text" direction="left"></chat-entry>
</ul>
</template>
Here is where im stuck, how i can add the components
<script>
Vue.component('chat-entry', require('./entry.vue'));
module.exports = {
data: function () {
return {
name: 'Default name',
message: 'Default message',
messages: null,
}
},
mounted: function () {
// This is the what i want to achive
this.messages.append('chat-entry', {direction: 'left', message: 'hello', name: 'HeatON'});
this.$http.get('/etc/yelp.xi').then(response => {
for (let q in response.body.arr) {
this.messages.append('chat-entry', {direction: 'left', message: q.message, name: q.name});
}
});
}
}
entry.vue
<template>
<div v-if="direction == 'left'">
<li>
<div class="message-data">
<span class="message-data-name"><i class="fa fa-circle you"></i> {{ name }}</span>
</div>
<div class="message you-message"> {{ message }} </div>
</li>
</div>
<div v-else>
<li class="clearfix">
<div class="message-data align-right">
<span class="message-data-name">{{ name }}</span> <i class="fa fa-circle me"></i>
</div>
<div class="message me-message float-right"> {{ message }} </div>
</li>
</div>
</li>
Is something like this even possible? if not, what is the proper approach?
Thanks in advance