How to send & receive object as a props in Vue.js - vue.js

I have a Product object and I am taking it from API call. So in parent component I want to send this object into the child object which is SoldTickets component.
So here is my parent component:
<template>
<section id="cart-page" class="row">
<div v-for="item in cart.attributes.items" :key="item.id">
<div class="col-lg-8 col-md-12 col-sm-12 col-xs-12">
<div class="title">WARENKORB</div>
<SoldTickets :item = item />
</div>
</div>
</section>
</template>
And my child:
<template>
<div id="sold-tickets">
<div class="card">
<div class="sold-tickets-actions properties">
<div class="sold-tickets-inner">
<div class="ticket-details">
<div class="ticket-prop">
<div class="ticket-name">{{ item.product_name }}</div>
<div class="ticket-type">{{ item.variation_name }}</div>
</div>
</div>
<DeleteButton #click.prevent="removeProductFromCart(item.id)" />
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
data: {
item: Object,
}
},
}
</script>
So I am quite new in Vue so I am not really confident with props. COuld you please help me with this.

You mostly have it right, but there are a couple of errors:
Your props aren't declared correctly in the child component, you shouldn't have the "data" in there. All props you want to declare go directly under the "props" key of the component declaration:
export default {
props: {
item: Object,
},
}
You're also missing quotes around the attribute value in the parent component, so that's invalid HTML:
<SoldTickets :item = item />
should be
<SoldTickets :item = "item" />

Just wrap the bound value with "" or '' like :
<SoldTickets :item="item" />

Related

Pass component as prop in object param

I have the following Card Grid set up in Vue3:
<template>
<div class="max-w-5xl mx-auto">
<div class="ml-20 pr-72">
<h2 class="text-4xl pb-8">{{ title }}</h2>
<p class="font-normal text-base pb-20">{{ description }}</p>
</div>
<div class="grid grid-cols-2 gap-5">
<div
v-for="card in cards"
:key="card.title"
class="rounded-xl py-6 px-5 bg-cover bg-center flex flex-col justify-between items-start h-60"
:style="{ backgroundImage: `url(${card.imageUrl})` }"
>
<div
class="rounded-full p-4 bg-gradient-to-r from-prospire-blue to-prospire-light-blue"
>
{{ card.icon }}
</div>
<p class="text-white font-light text-2xl">{{ card.title }}</p>
</div>
</div>
</div>
</template>
<script setup lang="ts">
const props = defineProps<{
title: string;
description: string;
cards: any[];
}>();
</script>
<style scoped></style>
Which i call using:
<CardGrid
:title="$t('aboutUs.cardGrid.title')"
:description="$t('aboutUs.cardGrid.description')"
:cards="[
{
title: $t('aboutUs.cardGrid.cards[0].title'),
imageUrl:
'https://images.pexels.com/photos/5595573/pexels-photo-5595573.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1',
icon: <BeakerIcon />,
},
]"
/>
This however gives me a BeakerIcon' refers to a value, but is being used as a type here. Did you mean 'typeof BeakerIcon'? error.. Is it possible to pass a 3rd party component (icon in this case), to a component in a way?
One option is to pass card.icon as a string, such as 'BeakerIcon' and do
<div class="rounded-full p-4 bg-gradient-to-r from-prospire-blue to-prospire-light-blue">
<component :is="card.icon" />
</div>
...granted the icon you pass has been registered as a component.
It also work without registering the component globally.
Here is an example on sfc.vuejs.org passing the imported components in the props.

How can I preserve data between switching between tabs in Vue?

I'm trying to learn some Vue, I have tab component it has 2 tabs with some dropdowns and text fields inside, the problem is when I switch between tabs it loss data like selected items from dropdowns or text values, I've tried with v-model but nothing, any help?
Here is the tab view
<script setup>
import { ref } from 'vue';
const nestedRouteItems = ref([
{
label: 'Personal',
to: '/uikit/ficha'
},
{
label: 'Seat',
to: '/uikit/ficha/seat'
},
]);
</script>
<template>
<div class="grid">
<div class="col-12 md:col-12">
<div class="card p-fluid">
<h5>Ficha</h5>
<div class="col-12 md:col-12">
<div class="card card-w-title">
<h5>Tab container</h5>
<p>Lorem ipsum dolor sit amet, consectetur.</p>
<TabMenu :model="nestedRouteItems" />
<router-view />
</div>
</div>
</div>
</div>
</div>
</template>
Here is the content of first tab:
<template>
<div class="flex align-items-center py-5 px-3">
<div class="card p-fluid" style="width:800px">
<h5>Datos personales</h5>
<div class="field">
<label for="name1">Nombre</label>
<InputText id="name1" type="text" />
</div>
</div>
</div>
</template>
Here is the content of second tab:
<script setup>
import { ref } from 'vue';
const dropdownItems = ref([
{ name: 'Principal', code: 'Principal' },
{ name: 'Laboral', code: 'Laboral' },
{ name: 'Familiar', code: 'Familiar' }
]);
const dropdownItem = ref(null);
</script>
<template>
<div class="flex align-items-center py-5 px-3">
<div class="card p-fluid" style="width:800px">
<h5>Domicilio</h5>
<div class="field">
<label for="tipoDomicilio">Tipo de domicilio</label>
<Dropdown id="tipoDomicilio" v-model="dropdownItem" :options="dropdownItems" optionLabel="name" placeholder="Elegir opciĆ³n..."></Dropdown>
</div>
</div>
</div>
</template>
You can use KeepAlive to do this.
<KeepAlive> is a built-in component that allows us to conditionally
cache component instances when dynamically switching between multiple
components.
If your tab components are dynamic then use KeepAlive like this-
<KeepAlive>
<component :is="tabComponent" />
</KeepAlive>
If you are using tab components individually then do like this-
<KeepAlive>
<tab-a></tab-a>
<tab-b></tab-b>
</KeepAlive>
You can read more about KeepAlive in the documentation.

VueJs 3 checkbox v-model on array of objects not working properly

I am having a hard time understanding why my v-model isn't working correctly
I have an 'service' object which contains a property 'actions' of type IAction[]
I also declared an object actions which is an array of IAction and am currently trying to bind checkBoxes to the actions array, but it is not working.
I feel like i am missing something obvious here but would need a little help understanding what it is.
Here is the relevant code
<script lang="ts">
let actions = [] as IAction[];
</script>
<template>
<div v-for="action in service.Actions" :key="action.Id" class="row">
<div class="col-md-12 d-flex">
<div>
<span class="pe-3">
{{ action.EnumName }}
</span>
<input v-model="actions" :value="action" type="checkbox" />
</div>
</div>
</div>
</template>
I would appreciate any feedback as I am relatively new to VueJs,
Thank you
I think you might not understand what you are doing in code, so I wrote examples.
Bad Code:
<script lang="ts">
let actions = [] as IAction[];
</script>
<template>
// here you iterate thro array and assign to action variable
<div v-for="action in service.Actions" :key="action.Id" class="row">
<div class="col-md-12 d-flex">
<div>
<span class="pe-3">
{{ action.EnumName }}
</span>
// Here you using actions with "s" on end so you using empty array declered in script
<input v-model="actions" :value="action" type="checkbox" />
</div>
</div>
</div>
</template>
If you are getting some data from service.Actions use them! v-model will override those actions if they are ref() or `reactive().
Example:
<script lang="ts">
let actions = [] as IAction[];
</script>
<template>
<div v-for="item in service.Actions" :key="action.Id" class="row">
<div class="col-md-12 d-flex">
<div>
<span class="pe-3">
{{ item.EnumName }}
</span>
<input v-model="item.is" :value="action" type="checkbox" />
</div>
</div>
</div>
</template>
If service.Actions is only array actions you want to add to array in script actions v-model is not a way you do that!
Probably code you need:
<script lang="ts">
const actions = ref([]) // Use refs everywhere !!! A specially in forms.
function deleteItem() {
// ToDo delete item from actions array
}
</script>
<template>
<div v-for="item in service.Actions" :key="item.Id" class="row">
<div class="col-md-12 d-flex">
<div>
<span class="pe-3">
{{ item.EnumName }}
</span>
<button #click="actions = [...actions, item]">ADD</button>
</div>
</div>
</div>
<div>
<div v-for="{ item, index } in actions" :key="item.id">
<span>{{ item.EnumName }}</span><button #click="deleteItem(index)">X</button>
</div>
</div>
</template>
As Mises pointed out, the v-model has to be a part of the same object as the v-for, so i just put my services and the actions array in an object
let foo = { services: serviceStore.services, actions: [] as IAction[] }

Nuxt Props pass to data and set images

how do i pass props into data ? i have a object that pass into prop and i want prop to set the image url with data "mainImage", must keep the mainImage.
<template>
<!-- start Product Header -->
<div class="ps-product__header">
<div class="ps-product__thumbnail" data-vertical="false">
<div class="ps-wrapper">
<div class="ps-product__gallery">
<div class="col-12 px-md-2 d-none d-md-block">
<div class="" style="cursor: pointer">
<b-img :src="mainImage" alt="" style="width: 100%" class="image" #click="showMainImage()"></b-img>
</div>
</div>
</div>
</div>
<div class="ps-product__variants">
<div class="col-12 d-none d-md-block my-4">
<div class="row">
<div class="col-3" v-for="(image, index) in product.images" :key="index">
<div class="thumbnail" style="cursor: pointer" #click="changeMainImage(image.src)">
<b-img :src="`${image.src}`" style="width: 100%" alt="" class="image" :class="mainImage === image ? 'activess' : ''"></b-img>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
here is the script
<script>
export default {
name: 'ShopHeader',
props: {
product: {
type: Object,
required: true
}
},
data() {
return {
mainImage: String,
}
},
methods: {
changeMainImage(image) {
this.mainImage = image
}
},
mounted() {
this.mainImage = this.product.image
console.log(this.mainImage)
}
}
</script>
sample : https://stackblitz.com/edit/nuxt-starter-pake3o?file=components%2FShopHeader.vue
when you type on the stackblitz url with /product, the image will show up but when you go through the link the image wont show up, so anyone know how to fix this problem ? i assume it was mounted only load once and component wont render after it.
add v-if to tag
<img v-if="mainImage" :src="mainImage" class="image">

Prop not getting updated in child component on value change

In my App component (parent) I have:
<div class="bg-dark text-white text-center p-3 content">
<div class="form-group">
<input class="form-control" v-model="dogBreed" />
</div>
<my-child-comp greeting="Hello from parent" v-bind:dog-breed="dogBreed" />
</div>
...
data() {
return {
dogBreed: "Pit Bull"
}
},
And in the child view:
<template>
<div class="bg-primary text-white text-center m-2 p-3 content">
<h3>Dog: {{ dog }}</h3>
</div>
</template>
...
props: ["greeting", "dogBreed"],
data() {
return {
dog: this.dogBreed,
}
},
I do get the initial value for dogBreed from the parent component inside of the child component, but when I change the value of the input field the same change is not reflected, why?
The prop in the parent component is not named properly, it should be the exact name of the props which is dogBreed you used in the child
component
<div class="bg-dark text-white text-center p-3 content">
<div class="form-group">
<input class="form-control" v-model="dogBreed" />
</div>
<my-child-comp greeting="Hello from parent" v-bind:dogBreed="dogBreed" />
</div>
...
data() {
return {
dogBreed: "Pit Bull"
}
},
Your child component can remain the same but use computed instead of data. Having the same name will not cause any computational
problems and using computed instead of data should fix up the dynamic
nature of your code.
<template>
<div class="bg-primary text-white text-center m-2 p-3 content">
<h3>Dog: {{ dog }}</h3>
</div>
</template>
...
props: ["greeting", "dogBreed"],
computed: {
dog(){
return this.dogBreed
}
},
If however you are keen on using dog-breed then you must rename the prop in you child component to dog-breed before binding it in your parent component.