Vue.js return and render templates - vue.js

I have 2 templates in which the child one loop through images.I need to send it to the parent as array of templates and then loop them in the parent in order to avoid duplicates.How to accomplish that? below are the codes :
Products.vue (parent):
<template>
<div>
<div class="u-repeater u-repeater-1"><!--product_item-->
<div
class="u-align-center-lg u-align-center-sm u-align-center-xl u-align-center-xs u-container-style u-products-item u-repeater-item">
<ImageComponent></ImageComponent>
</div><!--/product_item--><!--product_item-->
</div>
</div>
</template>
ImageComponent.vue: (child)
<template>
<div class="u-container-layout u-similar-container u-container-layout-1">
<div v-for="n in Object.keys(products[0]).length" :key="n">
<img alt="" :src="products[n].image" data-image-width="510" data-image-height="340"
class="u-expanded-width-lg u-expanded-width-md u-expanded-width-sm u-expanded-width-xl u-image u-image-default u-product-control u-image-1">
<div
class="u-align-center u-container-style u-expanded-width-xs u-group u-opacity u-opacity-70 u-palette-5-light-2 u-group-1">
<div class="u-container-layout u-container-layout-2">
<h4 data-animation-name="fadeIn" data-animation-duration="1000" data-animation-delay="0"
data-animation-direction="Up" class="u-product-control u-text u-text-1 animated fadeInUp-played"
style="will-change: transform, opacity; animation-duration: 1000ms;">
{{ products[n].model }}
</h4>
<div class="u-align-left u-product-control u-product-price u-product-price-1">
<div class="u-price-wrapper u-spacing-10">
<div class="u-hide-price u-old-price">$12</div>
<div class="u-price" style="font-size: 1.25rem; font-weight: 700;">{{ products[n].price }}</div>
</div>
</div>
<a href="#"
class="u-align-center-xs u-border-active-none u-border-hover-none u-btn u-btn-rectangle u-button-style u-none u-product-control u-text-palette-1-base u-btn-1">Add
to Cart</a>
</div>
</div>
</div>
</div>
</template>
<script>
import {mapState} from "vuex";
export default {
name: "ImageComponent",
data(){
return{
items:[
]
}
},
computed: {
...mapState({
products: (state) => state.products,
}),
}
}
</script>
<style scoped>
.u-palette-5-light-2, .u-body.u-palette-5-light-2, .u-container-style.u-palette-5-light-2:before, .u-container-layout.u-palette-5-light-2:before, .u-table-alt-palette-5-light-2 tr:nth-child(even) {
color: #111111;
background-color: unset;
}
</style>
Remark: not all codes are written, just to give the main idea.
Thanks for help.

Related

How to modify src attribute in image to make many cards VueJS

I want to have many card from my component and I want to change the src attribute on every image. Please help me to do it. Thankyou :D
<!---THIS IS MY PAGE FILE---->
<template>
<div>
<class-list :src="image1"></class-list>
<class-list :src="image2"></class-list>
<class-list :src="image3"></class-list>
<class-list :src="image4"></class-list>
</div>
</template>
<!---THIS IS MY COMPONENT FILE---->
<template>
<div>
<a-card hoverable style="width: 240px">
<img
slot="cover"
alt="example"
:src="image"
/>
<a-card-meta title="Europe Street beat">
<template slot="description">
www.instagram.com
</template>
</a-card-meta>
</a-card>
</div>
</template>
This kind of code should solve your use-case, here is a SFC link.
page
<template>
<div v-for="image in images">
<card :image="image"></card>
</div>
</template>
<script>
import Card from './Card.vue'
export default {
components: { Card },
data() {
return {
images: ['https://images.pexels.com/photos/5044497/pexels-photo-5044497.jpeg', 'https://images.pexels.com/photos/9365604/pexels-photo-9365604.jpeg', 'https://images.pexels.com/photos/10392192/pexels-photo-10392192.jpeg']
}
}
}
</script>
Card.vue
<template>
<div>
<img slot="cover" alt="example" :src="image" />
</div>
</template>
<script>
export default {
props: ['image']
}
</script>
<style scoped>
img {
width: 200px;
}
</style>
Here is the end result

How to send props in Vue

I am quite new in vue so I haven't understood the logic completely. My question is I have ticket and ticketlist components. So I am not on my ticket list component I am creating some tickets data and I want to show them according to the ticket component. To make it more clear here is my ticketlist component:
<template>
<section class="tickets">
<div class="container">
<div class="row">
<div class="col-12 col-md-3 mb-3">
<Ticket v-for="ticket in tickets" :key="ticket.id" :product="ticket"/>
</div>
</div>
</div>
</section>
</template>
<script>
import Ticket from './Ticket'
export default {
components: {
Ticket
},
data() {
return {
tickets: [
{
id: 0,
category: "Einzelkarte",
price: "€3,50",
tariff: [
"Wählen Sie eine Option",
"Erwachsene",
"Erwachsener erm.",
"Kinder / Jugendliche",
"Kinder / Jugendliche erm.",
],
available_amount: 23,
article_number: "2021.05.04-2673990197-1",
},
],
};
},
}
</script>
And also ticket component:
<template>
<widget type="ticket" class="--flex-column">
<div class="top --flex-column">
<div class="bandname -bold">Ghost Mice</div>
<div class="tourname">Home Tour</div>
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/199011/concert.png" alt="" />
<div class="deetz --flex-row-j!sb">
<div class="event --flex-column">
<div class="date">3rd March 2017</div>
<div class="location -bold">Bloomington, Indiana</div>
</div>
<div class="price --flex-column">
<div class="label">Price</div>
<div class="cost -bold">€{{ ticket.price }}</div>
</div>
</div>
</div>
<div class="rip"></div>
<div class="bottom --flex-row-j!sb">
<a class="btn button" href="#">ADD TO CART</a>
</div>
</widget>
</template>
<script>
export default {
props: ['ticket'],
}
</script>
<style scoped>
#import 'https://i.koya.io/flex/1.1.0.css';
*, ::after, ::before {
box-sizing: unset;
}
</style>
So, I am showing TicketList component in one of the page but the thing is it doesnt show anything. So I wonder how can I connect them together and show tickets data according to ticket component. I hope I am clear but if I am not I can answer you in the comments.
The probleme is the props name, you need to pass ticket as props and not product
...
<Ticket v-for="ticket in tickets" :key="ticket.id" :ticket="ticket"/>
...
or the contrary inside you Ticket component set :
props: ['product']

PrimeVue Toast displaying html tags

How can I implement displaying a link in a primevue toast message? I cannot use v-html directive and triple brackets do not work. Does anybody has another idea how to solve it?
A hacky way is to extends Toast component:
Here a codesandbox : https://codesandbox.io/s/extend-primevue-toast-o5o1c?file=/src/CustomToastMessage.vue
1. On your component
Import your custom toast component where you need to call this.$toast:
<template>
<div>
<CustomToast />
<CustomToast position="top-left" group="tl" />
<CustomToast position="bottom-left" group="bl" />
<CustomToast position="bottom-right" group="br" />
<div class="card">
<Button #click="test" label="test" />
</div>
</div>
</template>
<script>
import CustomToast from "./CustomToast.vue";
export default {
components: {
CustomToast,
},
data() {
return {
messages: [],
};
},
methods: {
test() {
this.$toast.add({
severity: "success",
summary: "Test",
detail: "<b>Test Bold</b>",
});
},
},
};
</script>
2. CustomToast.vue (extend primevue toast)
<template>
<Teleport to="body">
<div ref="container" :class="containerClass" v-bind="$attrs">
<transition-group name="p-toast-message" tag="div" #enter="onEnter">
<CustomToastMessage
v-for="msg of messages"
:key="msg.id"
:message="msg"
#close="remove($event)"
/>
</transition-group>
</div>
</Teleport>
</template>
<script>
import Toast from "primevue/toast/Toast.vue";
import CustomToastMessage from "./CustomToastMessage.vue";
export default {
extends: Toast,
components: {
CustomToastMessage,
},
};
</script>
3. CustomToastMessage (extend primevue toastmessage)
Add v-html where you want to have html
<template>
<div
:class="containerClass"
role="alert"
aria-live="assertive"
aria-atomic="true"
>
<div class="p-toast-message-content">
<span :class="iconClass"></span>
<div class="p-toast-message-text">
<span class="p-toast-summary">{{ message.summary }}</span>
<div class="p-toast-detail" v-html="message.detail"></div>
</div>
<button
class="p-toast-icon-close p-link"
#click="onCloseClick"
v-if="message.closable !== false"
type="button"
v-ripple
>
<span class="p-toast-icon-close-icon pi pi-times"></span>
</button>
</div>
</div>
</template>
<script>
import ToastMessage from "primevue/toast/ToastMessage.vue";
export default {
extends: ToastMessage,
};
</script>
There is an easiest solution.
Just implement your own template.
Example:
<Toast :position="toastPosition">
<template #message="slotProps">
<span :class="iconClass"></span>
<div class="p-toast-message-text">
<span class="p-toast-summary">{{slotProps.message.summary}}</span>
<div class="p-toast-detail" v-html="slotProps.message.detail" />
</div>
</template>
</Toast>

How to transfer data between components (siblings) Vue?

In the HeaderComponent method 'clickPrices' is called on click
<template>
<header>
<div class="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm">
<h5 class="my-0 mr-md-auto font-weight-normal">Company name</h5>
<nav class="my-2 my-md-0 mr-md-3">
<a class="p-2 text-dark" href="#">Features</a>
<a class="p-2 text-dark">Enterprise</a>
<a class="p-2 text-dark" #click="clickPrices()">Get pricing</a>
</nav>
<a class="btn btn-outline-primary " href="#">Sign up</a>
</div>
</header>
</template>
<script>
export default {
name: "HeaderComponent",
methods: {
clickPrices() {
...
},
},
}
</script>
<style scoped>
</style>
and there is a Pricing Component in which I make a request to the server in the method 'getPricing'
<template>
<div class="wrap-pricing">
<div class="pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
<h1 class="display-4">Pricing</h1>
<p class="lead">Quickly build an effective pricing table for your potential customers with this Bootstrap example. It’s built with default Bootstrap components and utilities with little customization.</p>
</div>
<div class="container">
<div class="card-deck mb-3 text-center">
<div class="card mb-4 shadow-sm">
<div class="card-header">
<h4 class="my-0 font-weight-normal">Lorem</h4>
</div>
<div class="card-body">
<h1 class="card-title pricing-card-title">$10 <small class="text-muted">/ mo</small></h1>
<ul class="list-unstyled mt-3 mb-4">
<li>Lorem</li>
<li>Lorem</li>
<li>Lorem</li>
<li>Lorem</li>
</ul>
<button type="button" class="btn btn-lg btn-block"></button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import router from '../routes.js';
import { axios } from 'axios';
export default {
name: "PriceComponent",
methods: {
getPricing() {
axios.get('api/pricing').then((response) => {
//some actions
router.push('prices');
});
},
},
}
</script>
<style scoped>
</style>
How should I process the result of the 'сlickPrices' HeaderComponent method?
Or am I waiting for your ways, how can I get data in another by clicking in one component
You can emit an event and let the parent component handle the fetching and pass the data as props to the child component.
Or another way is to directly listen to the event as follows
Component 1:
this.$root.$emit('clickPrices', data);
Component 2:
mounted() {
this.$root.$on('clickPrices', data => {
this.getPricing();
});
}
Check out the answer by #alex
Since you are using 2 independent components (one is not included in the other), you cannot pass props
Things you can do -
Instead of fetching all the prices on click, just create a created hook like so, which will fetch all the pricing details whenever your component is created -
created () {
this.getPricing()
},
methods: {
getPricing() {
axios.get('api/pricing').then((response) => {
//some actions
router.push('prices');
});
},
},
Use State and when a user clicks on the button, pricing details are fetched and added in the state. And you can just use the state anywhere in your application like so -
this.$store.state.prices
Let me know if it works, if not we will find some other solution for you!

How asynchronous render dom in Vue file?

I use $refs.height[index].offsetTop in the 1st part to computed same values, but $refs.height is in the 2rd part ,that render after the 1st part,so reload page has error TypeError: Cannot read property '0' of undefined.
I try comment <div>{{showNumber(index)}}</div>,then run npm dev,then recomment , it's work.
How render the 2rd part at first?
<template>
<div id="app">
//1st part
<div id="catalog">
<div v-for="(baike,index) in baikes">
<div class="catalog">
<h2>{{index+1}}.{{baike.name}}</h2>
<hr style="border:1px dashed #000; flex-grow: 1">
<div>{{showNumber(index)}}</div>
</div>
</div>
</div>
//2rd part
<div id="content">
<div v-for="(baike,index) in baikes" ref="height">
<h3 >{{index+1}}.{{baike.name}}</h3>
<p>{{baike.abstract}}</p>
<ul v-for="(info,key,index) in baike.info">{{key}}-{{info}}</ul></ul>
</div>
</div>
</div>
</template>
<script>
import baikeJSON from '../../items.json'
export default {
name: 'app',
data () {
return {
baikes: baikeJSON,
}
},
methods:{
showNumber(i){
return Math.ceil(this.$refs.height[i].offsetTop/1000)
}
},
}
</script>
Switch 2rd part and 1st part of position then add css
#app{
display:flex;
flex-direction:column-reverse;
}