Using Intertiajs with Element UI - vue.js

I am using Inertiajs
with Laravel and also trying to use Element UI components but as i use Menu component i am having following error in console, I just used example as given in Element Ui Components as i was testing.

I see 2 different errors in there, both of them are with props.
I assume your component is taking the route as a prop, and you are also using the route as a method, which you might have put inside methods: {} which is not allowed. Make sure you rename your method route to something else.
Note: As a matter of fact you can't have any data coinciding with each other. your props, data, computed props and methods all should have unique names.
You are trying to use v-model on the props directly which won't work in Vue. if the prop is a primitive (Number, String, Boolean etc). but you can pass Object or an Array which can hold a reference to the data. This is because reactivity in Vue can't keep track of props when passed as primitives.
More on prop mutations here: https://v2.vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow

Related

Vue.js list rendering diff: "same object" vs "has same values"

I have just hit a reactivity problem in Vue.js (2.6.12) component. It was not re-computing and re-rendering after its props were updated. The issue is that the component is used in a list with v-for with a key. The key was not changing, but the object's data was changing i.e. it was the same object, but its data was different.
The key is used as an optimization for diffing the list in v-for so it can re-use and re-order the same components without re-creating them. My original key was the object's id and the solution is to create the key from the id and all the object's changing data. That leads to other issues, like losing the component's internal data state, which has no need to be stored in a Vuex store.
My question is, is there a way in Vue.js (maybe in v3?) to tell in v-for not only if the object is the same (via key using object's id) but also if the object has the same data? Which will update the prop and re-computed and re-render the component without losing its internal data?
Funny thing is that the component's props are updating, it just does not re-compute and re-render. Verified via the Vue Devtools in a browser.
EDIT:
Here is an example where the reactivity does not work. It is using a Vuex store and the array for v-for is a computed property, which joins two properties from the store.
I just figured out that the problem is the joining of the values via the map on line 67: o.number = extras[o.id]. After replacing this with Vue.set(o, 'number', extras[o.id]) it is working!
This problem doesn't exist as described. Here is a small example of object reactivity working properly: https://jsfiddle.net/sh0ber/04s1jt8g
I'm guessing, however, that you're encountering the change detection caveat and need to use Vue.set.
The reason is now clear with the code example: Your computed creates a new property (number) on each Vuex obj that's not defined in Vuex at the time you set objs. If you had initialized the objs to have a number property as well, you wouldn't need Vue.set. Another way to prove it is to set o.text instead of o.number and you'll see it's reactive without Vue.set
(Btw, it makes more sense to do this computation in a Vuex getter instead of a computed; getters are computeds for Vuex. It's nice to decouple the logic from the component, and imagine you needed the result in multiple components)

Pass entire data item vs just id as Prop in Vue list when using VueX

I have a VueX state that contains a list of items. E.g.:
{
operations: Operation[]
}
We need to display each Operation as an item in a list. So we have an OperationList component and an OperationItem component.
When it comes to rendering the list (v-for), would it be recommended to pass the entire item as a prop or just the id and have the OperationItem read the data from VueX?
Basically:
<operation-item v-for="operationId in operationIds" :id="operationId" :key="operationId"/>
vs
<operation-item v-for="operation in operations" :operation="operation" :key="operation.id"/>
I think it might be a preference choice but in my projects I usually pass all the prop of the components that way :
<operation-item
v-for="operation in operations"
:key="operation.id"
:prop1="operation.prop1"
:prop2="operation.prop2"
:prop3="operation.prop3"
/>
I'm not sure if that's a good practice or not but in this case, it's more flexible, you don't need to give a structured object for it to render, you just have to give it all it's properties.
A bit like for a class constructor, I would pass all the necessary parameters separately instead of passing them in an $option array or Settings class.
For some components, it also doesn't make sense for them to be aware of the store, they should juste be "stupid" rendered components.
I hope it's clear enough that you get my point !
I'd say pass the entire item. That way your component doesn't need to know where the data came from and you would be able to reuse the component in situations where the data didn't come from Vuex.

Pass hidden data with vue-router

I would like to pass data when navigating from one route to another, but the data shouldn't be shown to the user in the URL, as it is with route parameters.
Instead, I want the data to stay "hidden" from the user, since, in my case, I want to pass an authentication key (which is pretty long and shouldn't necessarily be shown to the user).
Is this achievable using router.push()?
What I think I would do to solve this, is to define props, just below where you define your path, you can add props to it. See: Passing props to Route Components
Essentially you define what do you want to pass, an object, a value, whatever you need. And within your router-view component, you bind the prop that you want to pass.
For example:
: is shorthand for v-bind
<router-view :props-name-defined-in-router="value"></router-view>
Remember to use the proper casing in Vue.js See: Component name casing in templates
Additionally, I think this other question seems to fit your needs.
Passing props to Vue.js components instantiated by Vue-router

Object.assign breaks v-for (functional component)

I am creating a Vue component ("Polar") to layout divs in a circular pattern. It does so setting the inline styles.
Now, I am having a weird issue when I use the component. It happens only under a very specific set of circumstances:
I create multiple instances through v-for
The Polar component is a "functional" component
I pass the props as a referenced object (inline works fine!)
The propsObject contains a nested StylesObject
The custom Styles object gets merged as the first parameter of ObjectAssign()
What happens? All the instances in the v-for take on the value of the last item, like a closure was broken.
The code is a bit much to display here, so I have a codesandbox and github. The first test shows the issue: all items are displayed on top of each other. The second test demonstrates that I can pass the exact same propsObject, only inline, and it works. Reversing the arguments in Object.assign also makes it work, as does converting the component to a normal/non-functional one.
I suspect this is some sort of Vue bug (or at least undocumented behavior).
Quick answer:
Object.assign will change the first parameter (=target object). This caused my settingsObj to take on the other settings every time, until it had the settings of the last instance.
Easily resolved by changing
Object.assign(props.settingsObj, {setting: val, })
into
Object.assign({}, props.settingsObj, {setting: val, })
Sorry for blaming Vue, all my fault. Not exactly sure why this only happens with functional components, but it must be related to normal components being isolated in their own Vue instance.

Does $destroy function removes the Vue Custom component from cache

I construct deep nested tree of parent and children Vue custom components using my top level component dynamically and then I am updating the data from which all tree is constructed. Which has an effect of rendering the entire tree (its a form with various custom components). I refresh/rebuild the whole form after fetching the data (which is what vue do for reactive data) that itself tell me how to regenerate the view (its like a JSON Schema from which I render the entire view).
This is related to my other issue here.
I am observing a very weird behavior in my Vue Application. When I destroy all my children components and rebuild the data to force rendering the form, it appears that even after I have called $destroy on every child component...Vue is not entirely removing them from cache?
Does vue remove the component from cache if a $destroy is called ?
Because I do not see multiple components of the same type in the Vue component list in the Chrome Vue DevTool extension panel. But I see that the same custom event is handled twice by the same component. Same function that handle the events is getting called twice even though there is only one component visible in Vue DevTools of this type.
This only happens after I render the form. When the page is loaded for the first time every thing works. Then after I reset the form by destroying the child component and resetting the data to re-render the form, magically this child component start handling the event twice.. and in 3rd render it handle the events thrice. But I see only one component in google chrome VueJS DevTool extension panel. So my guess is that vue is still keeping the previously destroyed component in cache. I am trying to figure out how should I destroy those components in the cache.
If anyone has observed something similar and found a solution please let me know.
At the moment I am going to dig little bit more on my component keys (this particular component does not have explicit key set by me).
First and foremost, the vue documentation states:
vm.$destroy
In normal use cases you shouldn’t have to call this method yourself.
Prefer controlling the lifecycle of child components in a data-driven
fashion using v-if and v-for.
So instead of destroying and rebuilding the components manually yourself, you should really letting vue handle that via v-if and v-for. If the components aren't updating to your changes, you might be dealing with a reactivity issue.
As you mentioned that this is a deeply nested structure, the reactivity is key to keeping the components up to data with the data.
Vue does not allow dynamically adding new root-level reactive properties to an already created instance. However, it’s possible to add reactive properties to a nested object using the Vue.set(object, key, value) method:
Vue.set(vm.someObject, 'b', 2)
Inside of a component:
this.$set(this.someObject, 'b', 2)
Also, keep in mind that Vue should be doing the heavy lifting in regards to component management, while you should define the parameters by which a component is rendered.