Vuejs component not generating list on v-for - javascript

I've got a component that needs to render a list. However, every way I try it gives me some version of this error:
Property or method "messages" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property.
code:
Vue.component("vue-home-messages", {
props: ["user"],
methods: {
onClick: function(event, blah) {
console.log("CLICK: ", event);
console.log("Blah: ", blah);
}
},
data: function() {
return {
messages: [
{
id: 1,
sender: {
id: 234,
name: "Bob Barker"
},
subject: "Everything is AWESOME!",
body: "Etiam vel nisl ipsum."
},
{
id: 2,
sender: {
id: 234,
name: "Bob Barker"
},
subject: "Maybe Not",
body: "Etiam vel nisl ipsum."
}
]
}
},
template: `
<div class="col-lg-3">
<div class="card border-info mb-3" style="max-width: 20rem; margin: auto;">
<div class="card-header bg-primary text-white">New Messages</div>
<div class="card-body">
<div class="list-group">
<a v-for:"message in messages"
href="#"
class="list-group-item list-group-item-action"
#click="onClick">
{{ message.sender }} - {{ message.subject }}
</a>
</div>
</div>
</div>
</div>
`
});

change v-for:"message in messages" to v-for="message in messages"

Related

How to specify bootstrap accordion for data from API in vue js

I'm trying to create an order feed using accordion elements from bootstrap-vue and I am struggling with making only one element opened when I press it.
I've tried changing ids which are from api, but have no result.
HTML:
<div v-for="el in APIData" :key="el.id" >
<div class="accordion" role="tablist" :id="el.id">
<b-card no-body class="mb-1" :id="el.id">
<b-card-header header-tag="header" class="p-1" role="tab" :id="el.id">
<b-button block v-b-toggle.accordion-1 variant="dark">{{ el.name }}. Deadline: {{ el.deadline }} Price: <strong>{{ el.price }}</strong></b-button>
</b-card-header>
<b-collapse id="accordion-1" accordion="my-accordion" role="tabpanel" >
<b-card-body>
<b-card-text>
<div> <p> <strong>Posted:</strong> {{ el.date_posted }}. <br />{{ el.description }}</p> </div>
<a class= "button btn btn-dark">More</a>
</b-card-text>
</b-card-body>
</b-collapse>
</b-card>
</div>
</div>
Script:
<script>
import axios from 'axios'
export default {
name: 'Orders',
data () {
return {
APIData: [],
}
},
created () {
axios
.get('/api/v1/orders/')
.then(response => {
this.APIData = response.data
console.log(response.data)
})
.catch(err => {
console.log(err)
})
},
}
</script>
Example of data:
[
{
price: "179",
id: "1",
date_posted: "04_04_2022",
description: "some desc bla bla bla",
name: "some name",
deadline: "04_06_2022"
},
{
price: "189",
id: "2",
date_posted: "05_04_2022",
description: "another desc bla bla bla",
name: "some name",
deadline: "05_06_2022"
},
{
price: "199",
id: "3",
date_posted: "06_04_2022",
description: "another desc bla bla bla",
name: "some name",
deadline: "06_06_2022"
},
]
Again, I need to get opened only one accordion but get three instead e.g. because it seems to bootstrap that it is all one element.
You can simply achieve that by concatenating the el.id in the v-b-toggle attribute and the accordion id as well.
Working Demo :
new Vue({
el: '#app',
data: {
APIData: [{
id: 1,
name: 'Accordion 1'
}, {
id: 2,
name: 'Accordion 2'
}]
}
})
#app {
padding: 20px;
height: 350px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.22.0/dist/bootstrap-vue.js"></script>
<link rel="stylesheet" href="https://unpkg.com/bootstrap-vue#2.22.0/dist/bootstrap-vue.css"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#4.4.1/dist/css/bootstrap.min.css"/>
<div id="app">
<div v-for="el in APIData" :key="el.id" >
<p>
<b-btn v-b-toggle="`collapse-${el.id}`" variant="primary">Toggle {{ el.name }}</b-btn>
</p>
<b-collapse :id="`collapse-${el.id}`">
<b-card>
Collapse {{ el.name }} contents Here
</b-card>
</b-collapse>
</div>
</div>

VUEJS/X Data Template loads before my computed

first of all I'm sorry for my bad English, I'm using a translator.
I'm a beginner with VUE and VUE X, there are surely big mistakes.
I have a problem with VUE, currently I am trying to display a publication thanks to its ID.
Here is my DATA :
data(){
return {
list: [this.$store.dispatch('allPublications')],
id:'',
feed: '',
}
},
Here is my STORE action:
publicationId:({commit}, messages) => {
instance.get('/publications/' + messages.id)
.then(function(response){
commit('setMessage', response.data.publication)
console.log(response)
this.feed = response.data.publication.data
})
.catch(function(error){
console.log(error)
})
},
Here is my computed:
computed: {
...mapState({
user: 'profileUser',
publication: 'publicationFeed',
message: 'publicationInfos'
}),
message(){
return this.$store.state.message;
},
},
Here is my state :
setMessage: function(state, message){
state.message = message
},
Here is my template :
<template>
<div class="card-body" #click="publicationId(message.id)">
<span class="badge bg-secondary">{{ message.User.username }}</span>
<div class="dropdown-divider"></div>
<div class="card-text d-flex justify-content-between align-items-md-center">
<p class="card-text d-flex flex-start">{{ message.message }}</p>
</div>
<span class="message__date">{{ message.createdAt.split('T')[0]}}</span>
</div>
<img class="card-img-top" alt="..." :src="message.image">
Some screenshot to help you more :
VUE google chrome tool
Before reloading the page, everything is OK
After reloading the page, everything is going wrong
Everything works fine as long as I don't reload the page, as soon as I reload it I get an error, my computed value disappears and I can't get the data from my computed.
I have searched a lot of information without being able to solve this problem, thanks to you for the help!
It seems that i've solved this issue doing this :
data() {
return {
componentLoaded: false,
list: [this.$store.dispatch('allPublications')],
id: '',
feed: '',
}
},
In the mounted :
mounted() {
this.componentLoaded = true;
this.id = this.$route.params.id;
this.$store.dispatch('publicationId', { id: this.$route.params.id })
},
In the computed :
computed: {
message() {
if (!this.componentLoaded) {
return null
} else {
return this.$store.state.message;
}
},
},
And I add a v-if in the template
<template>
<div class="verification" v-if="componentLoaded === true">
<div class="card-body" #click="publicationId(message.id)">
<span class="badge bg-secondary">{{ message.User.username }}</span>
<div class="dropdown-divider"></div>
<div class="card-text d-flex justify-content-between align-items-md-center">
<p class="card-text d-flex flex-start">{{ message.message }}</p>
</div>
<span class="message__date">{{ message.createdAt.split('T')[0] }}</span>
</div>
<img class="card-img-top" alt="..." :src="message.image" />
</div>
<div v-else>
<h1>test</h1>
</div>
It worked for me, I hope it will help for those who needs.

Loop through several props objects in vue js

I want to simply loop through several props object data in my component, so for example:
I have created a card component and passing as props objects:
<template>
<div class="container">
<div v-for="(title, index) in titles" :key="index" class="counter">
<div class="title ">
<span>{{ title }}</span>
</div>
<div class="content">
<span>{{ values.value1 }}</span>
</div>
<div>
<Button :prop1="moreActions.prop1" :prop2="moreActions.prop2"
:prop3="moreActions.prop3" />
</div>
</div>
<!-- <div class="counter">
<div class="title">
<span>{{ titles.usersA }}</span>
</div>
<div class="content">
<span>{{ values.values2 }}</span>
</div>
<div>
<Button :prop1="moreActions.prop1" :prop2="moreActions.prop2"
:prop3="moreActions.prop3" />
</div>
</div> -->
// more div here.....
</div>
</template>
<script>
import Button from "../test/testButton";
export Test {
name: "Card",
components: {
Button,
},
**//Comment: I want to loop through each objects ( titles, values, moreActions)**
props: {
titles: {
type: Object,
default: () => ({}),
},
values: {
type: Object,
default: () => ({}),
},
moreActions: {
type: Object,
default: () => ({}),
},
},
};
</script>
and in app.vue , i am passing the data something like this:
export const test = createTest ({
.........
props: // I can say 'data' too
{
titles: {
testA: "testA",
usersA: "TestB",
testc: "test3",
textd: "Test4",
},
values: {
value1: "9000",
value2: "600",
value3: "100",
value4: "2",
ofTotal: " of 9",
},
moreActions: {
prop1: "Test",
prop2: "testIcon",
prop3: "test",
},
}
});
in the second div I can loop through like this and so on:
<div v-for="(value, index) in values" :key="index" class="content">
<span>{{ value }}</span>
</div>
but then it doesnot look goods, I want to loop through every props objects in one v-for loop instead giving v-for loop to each div. how can I do that in efficient way.
Thanks in advance!

How do I fetch JSON data with Vue and Axios

I'm trying to fetch product data from a JSON file, but can't get it to work.
I've tried several things and searched the internet for a solution but none of the examples on the internet equals my situation.
I'm new to both vue and axios, so please excuse my ignorance.
This is what I have so far:
Vue.component('products',{
data: {
results: []
},
mounted() {
axios.get("js/prods.json")
.then(response => {this.results = response.data.results})
},
template:`
<div id="products">
<div class="productsItemContainer" v-for="product in products">
<div class="productsItem">
<div class="">
<div class="mkcenter" style="position:relative">
<a class="item">
<img class="productImg" width="120px" height="120px" v-bind:src="'assets/products/' + product.image">
<div class="floating ui red label" v-if="product.new">NEW</div>
</a>
</div>
</div>
<div class="productItemName" >
<a>{{ product.name }}</a>
</div>
<div class="mkdivider mkcenter"></div>
<div class="productItemPrice" >
<a>€ {{ product.unit_price }}</a>
</div>
<div v-on:click="addToCart" class="mkcenter">
<div class="ui vertical animated basic button" tabindex="0">
<div class="hidden content">Koop</div>
<div class="visible content">
<i class="shop icon"></i>
</div>
</div>
</div>
</div>
</div>
</div>
`
})
new Vue({
el:"#app",
});
The json file is as follows
{
"products":[
{
"name": "Danser Skydancer",
"inventory": 5,
"unit_price": 45.99,
"image":"a.jpg",
"new":true
},
{
"name": "Avocado Zwem Ring",
"inventory": 10,
"unit_price": 123.75,
"image":"b.jpg",
"new":false
}
]
}
The problem is only with the fetching of the data from a JSON file, because the following worked:
Vue.component('products',{
data:function(){
return{
reactive:true,
products: [
{
name: "Danser Skydancer",
inventory: 5,
unit_price: 45.99,
image:"a.jpg",
new:true
},
{
name: "Avocado Zwem Ring",
inventory: 10,
unit_price: 123.75,
image:"b.jpg",
new:false
}
],
cart:0
}
},
template: etc.........
As the warnings suggest, please do the following:
Rename the data array from results to products since you are referencing it by the latter one as a name during render.
Make your data option a function returning an object since data option must be a function, so that each instance can maintain an independent copy of the returned data object. Have a look at the docs on this.
Vue.component('products', {
data() {
return {
products: []
}
},
mounted() {
axios
.get("js/prods.json")
.then(response => {
this.products = response.data.products;
});
},
template: `
//...
`
}
<div id="products">
<div class="productsItemContainer" v-for="product in products">
<div class="productsItem">
...
Also, since you're not using CDN (I think), I would suggest making the template a component with a separate Vue file rather than doing it inside template literals, something like that:
Products.vue
<template>
<div id="products">
<div class="productsItemContainer" v-for="product in products">
<div class="productsItem">
<!-- The rest of the elements -->
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Products',
data() {
return {
products: []
}
},
mounted() {
axios
.get("js/prods.json")
.then(response => {
this.products = response.data.products;
});
}
}
</script>
And then in your main JS file or anywhere else requiring this component:
import Products from './components/Products.vue';
new Vue({
el: '#app',
data() {
return {
//...
}
},
components: {
Products
}
})
<div id="app">
<Products />
</div>

access array of objects inside template

I make one collection Recipes and then define its schema and i have one array of objects ingredients in my schema and now i want to access those array of objects in my template but unable to show them can you please guide me how to do it?
collections.js
Recipes = new Mongo.Collection('recipes');
Recipes.attachSchema(new SimpleSchema({
name: {
type: String,
label: "Recipe Name",
max: 100
},
ingredients: {
type: [Object],
minCount: 1
},
"ingredients.$.name": {
type: String
},
"ingredients.$.amount": {
type: String
},
description: {
type: String,
label: "How to prepare ",
},
time: {
type: Number,
label: "Time (Minutes)",
},
image: {
type: String,
autoform: {
afFieldInput: {
type: "cfs-file",
collection: 'recipesImages',
label: 'Recipe Picture'
}
}
}
}));
router.js
Router.route('/show_recipe/:_id', {
name: 'show_recipe',
template: 'show_recipe',
data: function() {
return Recipes.findOne(this.params._id);
}
});
show_recipe.html
<template name="show_recipe">
<div class="container">
<div class="row">
<div class="col-md-8">
{{#with FS.GetFile "recipesImages" image}}
<img class="img-responsive mt" src="{{url}}"/>
{{/with}}
</div>
<div class="col-md-4" >
<ul class="list-group">
<h3> Ingredients</h3>
<li class="list-group-item">{{ingredients.name}} - {{ingredients.amount}}</li>
</ul>
</div>
</div>
<div class="row">
<div class="col-md-8">
<h4>{{name}}</h4>
<p> {{description}}</p>
</div>
</div>
</div>
</template>
You're only missing an {{#each}} to iterate over the ingredients array. Using it will set the data context to one element of the array and then you can just access the keys directly:
<h3> Ingredients</h3>
{{#each ingredients}}
<li class="list-group-item">{{name}} - {{amount}}</li>
{{/each}}

Categories