New vue component instance when prop changes - vue.js

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/

Related

VueJS: Transition from dynamic component with :key isn't working

I have the following component:
<transition name='component-fade' mode='out-in'>
<component
:is='marketType'
:key='market.id'
:market='market'
:match='market.match'
/>
</transition>
I'm noticing the transition works well the marketType has changed, fully changing from different components. However, it is not working when the component doesn't change, but the key does. Vue seems to be instantly replacing it to be efficient, and ignores the fact that the key has changed.
The docs show an example of transition between dynamic components but they don't have examples of both a dynamic component swap + using a key at the same time.
I need the transition to activate when the data changes, regardless of whether the same type of component rendered.
How can I accomplish this?

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 draggable items between 2 components

I have a component that displays a list. I have another component that also displays a list.
They sit together on another component eg:
<template>
<div>
<my-component-1 :items="listItems1"/>
<my-component-2 :items="listItems2"/>
</div>
</template>
Is it possible to use a library such as vue-draggable to drag items from one component to the other?
Thanks
Yeah.
vuedraggable support many Sortable events like move, update ...
you can get new index and old index with this events and change items with indexes in your data().
https://www.npmjs.com/package/vuedraggable#events

VueJs - Deleting a File-input component from a list

I'm still pretty new to vue.js.
I recently created some vue components to tidy up my html. The components are different inputs like text and checkbox. They update the parents data using $emit('input', val). And make sure that the components are up-to-date using props and watch() on those props.
Now there is a problem with using watch() on <input type="file />, since you cannot set the input value like you can on other input types.
Using this example:
https://jsfiddle.net/minde281/nyu73dz6/25/
I have a list of, in this case, items on a shoppinglist. You can add an image for each item.
The image is loaded and added to the list. This works fine.
To get my problem:
add an image to item1
delete that item by clicking the X-button
The result is now that item2 will have that image on the <input type="file" />. The preview works as expected since this can be set through script and therefore use watch(). But somehow vue removes the wrong part of the html markup causing the last one to be removed.
Is there a different way to solve this problem? Or is there a way to tell vue to remove the correct part of the html markup?
-Minde
Vue tries to reuse the component and thats why the selected file is in the second input after deleting the component.
To prevent that you should use the key binding like this:
<li v-for="(item, index) in items" :key="item.name">
Now the hole component gets removed and everything should work as expected.

Vue component not updating after parent state change

I have Vue component which receives json data from props, after this render child components using v-for and pass this data as prop. Everything works fine until i try to remove one item from this list, when i remove it, it removes element incorrectly. In vue devtools i see that parent receives data correctly but not renders it properly. can anyone help me?
here is my code: https://gist.github.com/giokaxo/3d291b9b7b8ef97f81dc83799c430302
Use "key" attribute when rendering elements using v-for, for example:
<p v-for="(product, index) in order.products" :key="i">..</p>
The relevant documentation is here:
You can directly use v-for on a custom component, like any normal
element:
<my-component v-for="item in items" :key="item.id"></my-component>
In 2.2.0+, when using v-for with a component, a key is now required.
However, this won’t automatically
pass any data to the component, because components have isolated
scopes of their own. In order to pass the iterated data into the
component, we should also use props:
<my-component
v-for="(item, index) in items"
v-bind:item="item"
v-bind:index="index"
v-bind:key="item.id">
</my-component>
The reason for not automatically injecting item into the component is because that makes the component
tightly coupled to how v-for works. Being explicit about where its
data comes from makes the component reusable in other situations.
And here:
When Vue is updating a list of elements rendered with v-for, it by
default uses an “in-place patch” strategy. If the order of the data
items has changed, instead of moving the DOM elements to match the
order of the items, Vue will simply patch each element in-place and
make sure it reflects what should be rendered at that particular
index.
...
To give Vue a hint so that it can track each node’s identity, and thus
reuse and reorder existing elements, you need to provide a unique key
attribute for each item. An ideal value for key would be the unique id
of each item.