Pass props to v-dialog from parent to child in Vue - vue.js

I'm new to Vue and have looked at some answers regarding my problem in which, I want to pass an id (for example 0099) from my child component to the parent via v-model. Is this possible, to pass an ID this way?
Here's my child code:
<template>
<v-dialog v-model="show" width="unset">
<v-card class="px-15 py-8" elevation="0">
<div class="px-6 py-8 mb-n4 text-center">
<span class="lucky-point--text text-h6">
Are you sure you want to access this employee?
</span>
</div>
</v-card>
</v-dialog>
</template>
What I want is that in v-model="show" I want to also include some id of an employee. Example v-model="show[0099] to the parent.
my parent code:
<ClaimDialog
:id="item.employeeid"
/>
although I used some props.
props: {
id: Number
}
Once I click from parent dialog it gets stacked on top of one another. I have found one answer but on my side its a bit tricky, since I'm new to Vue, and this approach is different from mine, since mine has a child component. Here's that question: Why are my dialogs stacked on top of one another? (Vuetify)

If you need to pass data from a child to a parent, then you must use $emit
Here is an example of a question and answer
Here is a link to the official documentation
If these links do not help you, then update the question: what event should the data be transmitted on, and how your components are connected (more code from your components)

Related

How to move a Vue component around without loosing its state

I have a Vue3 wrapper component that implements a magnification feature in a dashboard. It displays an inner Vue component in two different ways. One is inline and the other is in a full-page pop-up for magnification. The gist of the template (I'm using Vuetify) is:
<template>
<v-card>
<!-- normal location -->
<component v-if="!full_page" :is="innerComponent" />
<!-- magnified full-page version -->
<v-dialog v-if="full_page">
<v-card>
<component :is="innerComponent" />
</v-card>
</v-dialog>
</v-card>
</template>
The above works in general, except that there are two different components in play. This means that if the non-magnified component has internal state then that is lost when switching to the magnified version. I see threee options:
guarantee that all state, even transient one, is maintained external to the component
reach into the component to clone state
ensure Vue moves the component from one spot in the DOM to the other
My question is whether the third option is possible?
With Vue 3 you can use Teleport component to move a component around.
You can do like that:
<div id="div1"></div>
<div id="div2"></div>
<Teleport :to="position ? '#div1' : '#div2'">
<YourComponent/>
</Teleport>
An important note is that
The teleport to target must be already in the DOM when the
component is mounted.
So you need some extra work to make it work with your own code.
Live demo

When exactly are keys useful in Vue?

I still don't quite get the use of keys even after reading through the docs but I understand that it has to do with keeping each item unique. I've been solely adding a key when using a v-for and only to the outer most parent (not the children of the v-for. Are there any other situations when keys should be used?
<div v-for="(person,index) in people" :key="index>
<div class="name-label>
<img :src="person.img/>
<div> {{ person.name }} </div>
</div>
</div>
The key directive alongside v-for, is used to uniquely identify each parent element rendered on the v-for operation.
The same happens in Reactjs:
{elements.map((value, index) => {
return <li key={index}>{value}</li>
})}
The key directive in Vuejs is also used to force Vuejs to re-render an element that contains it every time :key receives a new value.
As #firmino-changani indicated, other uses of key is if you want Vue to force a re-render or replacement of an element or component. See key special attribute documentation:
It can also be used to force replacement of an element/component
instead of reusing it. This can be useful when you want to:
Properly trigger lifecycle hooks of a component
Trigger transitions For example:
<transition>
<span :key="text">{{ text }}</span>
</transition>
When text changes, the <span> will always be replaced instead of patched, so a transition will be triggered.
Another example, lets say you have a dialog popup to add new data and another component that needs updating once the new data was entered via the popup. This second component might have logic inside lifecycle hooks like onMounted etc. Using a :key you can force re-rending this component once the dialog popup is saved e.g.
<template>
<page>
<add-data-popup #save="myKey++" />
<show-data :key"myKey" />
</page>
</template>
From the vueJs docs around Keys:
The key special attribute is primarily used as a hint for Vue’s virtual DOM algorithm to identify VNodes when diffing the new list of nodes against the old list.
To simply put it, if a div is rendered via a For-loop the div will be identical to each other div. When a user clicks on one of these Div's and you instantiate a #click function, how will vueJs know what differentiates each of these divs? How will vue know how to reorder these div's in the correct order if you remove a middle div?
VueJs uses the key to know how to reorder the DOM when an action is taken on one of these objects in your For loop.
Here is an article fully explaining about vueJs keys, and more details on the VueJS reactivity engine which is good to know about: https://www.telerik.com/blogs/in-vue-when-do-i-actually-need-the-key-attribute-and-why

Vue: communicating parameters from app to component and back, using computed properties

Sorry for the beginner question (I'm fairly sure this will be a duplicate, but I actually can't figure out what terms to use in order to find it). I just started with Vue.
I am just getting started with Vue, and following this course (https://www.vuemastery.com/courses/intro-to-vue-js/communicating-events). In this problem, there is (and here I don't know the term, so I'm going to go with...) app-level data parameter called cart. cart is an array which holds the id of each item a user has added to cart.
The problem tells us to add a button to remove items from the cart.
I ran into problems trying to create a computed property, which would allow me to hide the "remove" button in the event the selected item is not in the cart (eg. `
Communicating data from the app-level (the cart array), to the component-level (to a computed property in the product component), so that I could use something like :hidden="!inCart" on the "Remove from Cart" button, which is itself defined in the component. inCart would be a computed value here.
Communicating the selected product from the component to the app-level, computing inCart at the app level, then using the computed value at the component-level.
Either way, I can't seem to figure out how to do this in the way I would want to, which would look something like how v-bind operates. Namely, I think I may be able to hack together a solution using methods (which I believe have to be triggered by certain events), but I don't understand how I might go about this using built-in functionality such that the value of inCart is dynamically auto-computed.
Maybe there would be an answer to this in the next few courses, but I don't see us covering that in the intro material. Sorry for the neophyte question. Thank you in advance.
In Vue the way you communicate "state" from higher-level objects to lower-level objects is through props.
So, assuming your app looks something like...
<MyApp>
<MyShoppingPageWithItems>
<MyItem></MyItem>
<MyItem></MyItem>
<MyShoppingPageWithItems>
</MyApp>
You need to pass the cart object down as a prop.
So in your MyShoppingPageWithItems template, you'll have something like...
<template>
<div>
<MyItem v-for="item in items" :item=item :cart="cart"?
</MyItem>
</div>
</template>
And in your item template...
<template>
<div>
<div>
{{item.name}}
</div>
<div v-if="cart.includes(item.id)">
Remove button or whatever
</div>
</div>
</template>
Not that the .includes() method is a native JavaScript method, which you can read more about here.
Edit
To reference a prop in a computed property (or anywhere else in a Vue component), just refer to this.propName, as demonstrated here in the Vue docs.
So, if you want to create a computed property, you can do the following:
<template>
<div>
<div>
{{item.name}}
</div>
<div v-if="isInCart">
Remove button or whatever
</div>
</div>
</template>
<script>
export default {
props: ['cart', 'item'],
computed: {
isInCart() {
return this.cart.includes(this.item.id)
}
}
}
</script>
Note that the formula is the exact same as above, but just includes this. for cart and item. In templates, the this. is implied when referring to props, data, and computed properties.

New vue component instance when prop changes

Our single page application has different views based on components. Due to the one-way-dataflow each property in the child gets updated when the respective value bound in the parent changes.
Is it possible to get a completely new component instance in case a property has changed? In combination with a transition I want to achieve that the old component slides out while the new one based on the latest property values slides in.
I am really looking forward for some cool input.
You can do it by updating the key:
<transition name="fade">
<hello :key="key"></hello>
</transition>
Then update the key:
<button #click="key++">Reload</button>
See my example fiddle:
https://jsfiddle.net/eaguad1337/w9fb1pv2/

Oddity with templates and root node with vue.js

I think this is possibly a bug I've stumbled across, not sure. I'm getting this Vue.js warning for a component:
vue.js:2611 [Vue warn]: Cannot use <template> as component root element because it may contain multiple nodes:
The problem seems to be this:
<template id="tpl-field">
<template v-if="fieldType==='checkbox-inline'">
<label class="checkbox-inline">[SNIP]</label>
</template>
<template v-else>
[SNIP]
</template>
</template>
So I have two template nodes, which seems to be the multiple nodes it's choking on (certainly each of the template nodes contains just a single node). Yet this is an if-else in Vue - if one of the nodes is present, the other logically cannot be.
Demo of the problem here: https://jsfiddle.net/jonmor51/Ldz3k0jp/1/. If I wrap everything in a div, it works. But without, it fails. (Unfortunately, in the context where I want to use this, namely for inline checkboxes within a Bootstrap grid, wrapping in a div breaks things).
Not sure if this will solve your problem with bootstrap... but you could wrap you inner templates with a <transition> tag and set a key to each one.
Please check this working fiddle
https://jsfiddle.net/AldoRomo88/7c7znu3p/
helpful thing - just use div display: contents as a root of the component and browser will ignore that element and consider child elements (which can be many) as children of upper dom element
<div style="display: contents">
<template v-if="...">
<template v-for="..."> ...
</template>
<template v-if="...">
</template>
</div
works even inside tables!
The inner templates direct children, are they single elements? If so, you can just remove the inner templates and move v-if to the label.
Or, just use span rather than div as your quick fix, which won't break inline elements' style.