Looping through data in Vue.js - vuejs2

I have three list items and I am trying to display them using Vue.js. It works fine when displaying single items but when I try to display multiple items then its not working. Code pen link
var data = {
products : [
{
"id": "532",
"name": "Bamboo Thermal Ski Coat",
"description": "You'll be the most environmentally conscious skier on the slopes - and the most stylish wearing our fitted bamboo thermal ski coat, made from organic bamboo with recycled plastic down filling. ",
"image": "https://cdn.shopify.com/s/files/1/0133/3248/0100/products/JAYCOSIN-Women-s-Coat-Fashion-Womens-Ladies-Warm-Faux-Fur-Comfortable-Coat-Sexy-Jacket-Winter-Solid_2048x2048.jpg?v=1574355729",
"price": "99"
},
{
"id": "532",
"name": "Bamboo Thermal Ski Coat",
"description": "You'll be the most environmentally conscious skier on the slopes - and the most stylish wearing our fitted bamboo thermal ski coat, made from organic bamboo with recycled plastic down filling. ",
"image": "https://cdn.shopify.com/s/files/1/0133/3248/0100/products/JAYCOSIN-Women-s-Coat-Fashion-Womens-Ladies-Warm-Faux-Fur-Comfortable-Coat-Sexy-Jacket-Winter-Solid_2048x2048.jpg?v=1574355729",
"price": "99"
},
{
"id": "532",
"name": "Bamboo Thermal Ski Coat",
"description": "You'll be the most environmentally conscious skier on the slopes - and the most stylish wearing our fitted bamboo thermal ski coat, made from organic bamboo with recycled plastic down filling. ",
"image": "https://cdn.shopify.com/s/files/1/0133/3248/0100/products/JAYCOSIN-Women-s-Coat-Fashion-Womens-Ladies-Warm-Faux-Fur-Comfortable-Coat-Sexy-Jacket-Winter-Solid_2048x2048.jpg?v=1574355729",
"price": "99"
}
]
}
var app = new Vue({
el: "#app",
data: data
});
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div class="container" id="app">
<div class="row d-flex mb-3 align-item-center" v-for="item in products">
<div class="col-sm-4">
<a :href="href">
<img class="img-fluid" :src="item.image" :alt="item.name" width="250" height="300">
</a>
</div>
<div class="col">
<h3 class="text-info">{{ item.name}}</h3>
<p class="mb-0">{{ item.description}}</p>
<div class="h5 float-right">$ {{item.price}}</div>
</div>
</div>

<a :href="href"> is accessing an undefined variable (href)
Use <a :href="item.href"> and then add a href to each item.

Related

Vue3 is cutting properties from custom Elements used in App

i want to include an external library in my Vue3 app. But when i try to inlcude them in my app, but some properties the element uses get cutted by Vue. Maybe someone can explain me this behaviour and how to fix this.
The attribute i am pointing on is "secondary"
vite.config.ts:
...
plugins: [
vue({
template: {
compilerOptions: {
// treat all tags with a dash as custom elements
isCustomElement: (tag) => {
return tag.includes("-");
},
},
},
}),
],
...
index.html
<div class="container">
<atom-button secondary>Test</atom-button>
<my-vue-comp></my-vue-comp>
</div>
in my component:
<template>
<div ref="root">
<atom-button secondary>Test</atom-button>
</div>
</template>
output in DOM:
<div class="container">
<atom-button secondary="" role="button" tabindex="0" type="button" aria-disabled="false">Test</atom-button>
<my-vue-comp>
<div>
<atom-button role="button" tabindex="0" type="button" aria-disabled="false">Test</atom-button>
</div>
</my-vue-comp>
</div>

vuejs props Avoid mutating a prop directly

my application is working fine, but here is the issue where I get an error, when I click on any of the menu, I get the following error, please help. good work.
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "selectedPost"
TabloStart.vue
<template>
<section class="section-content padding-y bg">
<div class="container">
<div class="row">
<TableMenu :posts="posts" :selectedPost="selectedPost"></TableMenu>
</div>
</div>
</section>
</template>
<script>
export default {
name: "TabloStart",
data() {
return {
posts: [
{
id: 1,
title: "Cat Ipsum",
content:
"<p>Dont wait for the storm to pass, dance in the rain kick up litter decide to want nothing to do with my owner today demand to be let outside at once, and expect owner to wait for me as i think about it cat cat moo moo lick ears lick paws so make meme, make cute face but lick the other cats. Kitty poochy chase imaginary bugs, but stand in front of the computer screen. Sweet beast cat dog hate mouse eat string barf pillow no baths hate everything stare at guinea pigs. My left donut is missing, as is my right loved it, hated it, loved it, hated it scoot butt on the rug cat not kitten around</p>"
},
{
id: 2,
title: "Hipster Ipsum",
content:
"<p>Bushwick blue bottle scenester helvetica ugh, meh four loko. Put a bird on it lumbersexual franzen shabby chic, street art knausgaard trust fund shaman scenester live-edge mixtape taxidermy viral yuccie succulents. Keytar poke bicycle rights, crucifix street art neutra air plant PBR&B hoodie plaid venmo. Tilde swag art party fanny pack vinyl letterpress venmo jean shorts offal mumblecore. Vice blog gentrify mlkshk tattooed occupy snackwave, hoodie craft beer next level migas 8-bit chartreuse. Trust fund food truck drinking vinegar gochujang.</p>"
},
{
id: 3,
title: "Cupcake Ipsum",
content:
"<p>Icing dessert soufflé lollipop chocolate bar sweet tart cake chupa chups. Soufflé marzipan jelly beans croissant toffee marzipan cupcake icing fruitcake. Muffin cake pudding soufflé wafer jelly bear claw sesame snaps marshmallow. Marzipan soufflé croissant lemon drops gingerbread sugar plum lemon drops apple pie gummies. Sweet roll donut oat cake toffee cake. Liquorice candy macaroon toffee cookie marzipan.</p>"
}
],
selectedPost: null
}
}
}
</script>
TableMenu.vue
<template>
<div class="posts-tab">
<ul class="nav nav-tabs">
<li v-for="post in posts"
v-bind:key="post.id"
v-on:click="selectedPost = post"
class="nav-item"
>
<a href="#" v-bind:class="{ active: post === selectedPost }" class="nav-link">
{{ post.title }}
</a>
</li>
</ul>
<div class="selected-post-container">
<div v-if="selectedPost"
class="selected-post">
<h3>{{ selectedPost.title }}</h3>
<div v-html="selectedPost.content"></div>
</div>
<strong v-else>
Click on a blog title to the left to view it.
</strong>
</div>
</div>
</template>
<script>
export default {
name: "TableMenu",
data() {
return {}
},
props: {
posts: [],
selectedPost: null,
}
}
</script>
v-on:click="selectedPost = post" is the culprit; selectedPost is a prop here and you cannot assign to a prop.
There are two different solutions depending on what you want:
Make selectedPost a local data property instead of a prop. You can then modify selectedPost but since it is no longer a prop, you cannot accept selectedPost from the parent anymore (but you're not really doing that anyway).
data() {
return {
selectedPost: null
}
}
Instead of modifying selectedPost directly, you should emit an event which the parent can handle to update its data. The convention is to emit an event named like update:selectedPost which will make it work with the .sync modifier.
Change the click handler to:
#click="$emit('update:selectedPost', post)"
Then in the parent, update as follows:
<TableMenu
:posts="posts"
:selectedPost="selectedPost"
#update:selectedPost="selectedPost = $event"
></TableMenu>
Or you can use .sync to make the above a bit simpler (it does the same thing):
<TableMenu
:posts="posts"
:selectedPost.sync="selectedPost"
></TableMenu>

Vue Property XXX was accessed during render but is not defined on instance

Could someone please advise why I am getting the error message: Property XXX was accessed during render but is not defined on instance?
Context:
I have created a "project" component and I am displaying 3 of these child components inside of a "projectgrid" parent component. Each project has an object defined in the "projectgrid" data function. I want to iterate over these project data objects to render all of the child elements. The base configuration is appearing but none of the props I am passing from the data objects (from parent to child) are appearing and I am getting the above error.
projectgrid parent component:
<template>
<div class="project-container">
<div class="container-fluid">
<div class="row">
<div class="col" v-for="(project, index) in projects" :key="index">
<Project />
</div>
</div>
</div>
</div>
</template>
<script>
import Project from "#/components/Project.vue";
export default {
name: "Projectgrid",
components: {
Project,
},
data() {
return {
projects: [
{
title: "Project 1",
image: "",
langInfo: "loremipsum",
description: "loremipsum",
codeLink: "loremipsum",
siteLink: "loremipsum",
},
{
title: "Project 2",
image: "",
langInfo: "loremipsum.",
description: "loremipsum",
codeLink: "loremipsum",
siteLink: "loremipsum",
},
{
title: "Project 3",
image: "",
langInfo: "loremipsum.",
description: "loremipsum",
codeLink: "loremipsum",
siteLink: "loremipsum",
},
],
};
},
};
</script>
project child component:
<template>
<div class="project">
<div class="card" style="width: 18rem">
<img
src="https://images.unsplash.com/photo-1597838816882-4435b1977fbe?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=2049&q=80"
class="card-img-top"
alt="..."
/>
<div class="card-body">
<h5 class="card-title">{{ title }}</h5>
<h6 class="card-lang-info">Written with {{ langInfo }}</h6>
<p class="card-text">
{{ description }}
</p>
</div>
<div class="card-body">
<a :href="codeLink" class="card-link"><i class="bi bi-github"></i></a>
<a v-if="(title = Portfolio)" class="card-link project-link"
><i class="bi bi-link-45deg"></i
></a>
<a v-else :href="siteLink" class="card-link project-link"
><i class="bi bi-link-45deg"></i
></a>
</div>
</div>
</div>
</template>
<script>
export default {
name: "Project",
props: {
portfolio: {
title: String,
image: Image,
langInfo: String,
description: String,
codeLink: String,
siteLink: String,
},
},
};
</script>
The projects are successfully iterated over and they are displaying with the hard coded data, but none of the props are displaying. Someone please assist? Thanks

Simplest v-for example doesn't work in <li v-for="todo in todos">

I've started learning Vue.js and I immediately hit a bump.
<body>
<div id="app">
<span v-if='show'>{{ message }}</span>
</div>
<ol>
<li v-for="todo in todos">
{{ todo }}
</li>
</ol>
</body>
var app = new Vue({
el: '#app', // elementul pe care il controleaza Vue
data: { // datele aplicatiei (model)
message: "Hello Vue",
show: true,
todos: [
"Learn JavaScript",
"Learn Vue.JS",
"Learn React",
"Be Free !"
]
}
});
Using the above code should display :
Hello Vue
1.Learn JavaScript
2.Learn Vue.JS
3.Learn React
4.Be Free !
Instead this is what I get:
Hello Vue
1.{{ todo }}
I am watching a video tutorial and my code is identical to the teacher's; his works, mine does not.
The console is empty. There is no error, no warning message, no nothing. It just does not work.
I have also tried using {{ todo.text }} but with no luck.
Your list is outside of the main div element, so it won't be part of the component's template.
Fix is:
<body>
<div id="app">
<span v-if='show'>{{ message }}</span>
<ol>
<li v-for="todo in todos">
{{ todo }}
</li>
</ol>
</div>
</body>

Transition on class change property

I currently have a vue component that I use to select drinks to be ordered.
You can increment or decrement the amount of drinks per type.
There are 2 buttons (Increment and decrement), the decrement button needs to be hidden when the amount of ordered drinks for that type is equal to 0. This can easily be accomplished by using :class="drink.amount > 0 ? 'visible':'invisible'" using the tailwind classes which sets visibility:hidden css property. When using this method it looks like:
Now I tried to implement css animations (sliding the button underneath the drink block to hide it and later hide from dom). I want to implement this using the vue transition component since this is heavily used throughout the application.
Now I have the problem that the vue transition component only works with a limited amount of vue functions among which v-if and v-show. v-if removes the html from the dom. v-show sets the property display:none both of these functions have the effect of shifting the buttons:
I would like to known how I can use the vue transition component and get the requested aligned buttons as I got without the animation.
<div v-for="drink in drinks" class="w-full flex">
<div class="mx-auto flex">
<transition name="transition-slide-right">
<div class="bg-white w-16 h-16 flex justify-center items-center mt-12"
v-show="drink.amount">
<p>-</p>
</div>
</transition>
<div class="bg-brand w-32 h-24 flex justify-center items-center my-8 z-30">
<p>{{drink.name}} ({{drink.amount}})</p>
</div>
<div class="bg-white w-16 h-16 flex justify-center items-center mt-12">
<p>+</p>
</div>
</div>
</div>
And accompanying script.
<script>
export default {
name: "CreateTransaction",
data: function() {
return {
drinks: [
{name: 'Cola', price: '1.0', amount: 1},
{name: 'Sinas', price: '1.0', amount: 0}
],
}
}
}
</script>
Finally the css:
.transition-slide-right-enter-active, .transition-slide-right-leave-active {
transition: transform .5s;
}
.transition-slide-right-enter, .transition-slide-right-leave-to {
transform: translateX(100%);
}
As a current workaround I removed the transition component, added the transition-slide-right-enter-active class and if the count == 0 I conditionally add the transition-slide-right-enter class. This does not hide the element but hiding it is not required since I is moved underneath the center block.
you can try the following code
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
<div class="row" id="todo-list-example">
<div v-for="(drink,index) in drinks" class="w-full flex">
<transition name="transition-slide-right"><button v-show="drink.amount" type="button" class="btn btn-danger" v-on:click="click1(index)">-</button></transition>
<a class="btn btn-success" >{{drink.name}} ({{drink.amount}})</a>
<button type="button" class="btn btn-danger" v-on:click="click2(index)">+</button>
</div>
</div>
<style>
.w-full{margin:10px 0px;}
.transition-slide-right-enter-active, .transition-slide-right-leave-active {
transition: transform .5s;
}
.transition-slide-right-enter, .transition-slide-right-leave-to {
transform: translateX(100%);
}
</style>
<script>
new Vue({
el: '#todo-list-example',
data(){
return {
drinks: [
{name: 'Cola', price: '1.0', amount: 1},
{name: 'Sinas', price: '1.0', amount: 1}
],
}
},
methods:{
click1:function(index){
this.drinks[index].amount=this.drinks[index].amount-1;
},
click2:function(index){
this.drinks[index].amount=this.drinks[index].amount+1;
}
}
})
</script>