Vuetify v-data-table drag and drop - vue.js

I am using V-data-table along with vuex store. Below are the points how I configured my v-data-table
Disabled sort on each column
bind the v-data-table items with vuex state store data
using sortablejs to drag and drop the rows
Problem:
When I drag and drop the rows in the v-data-table the I am updating the vuex store(updating the index value on the objects in array with the table row index value). Vuex is updating properly but the data rendered in the v-data-table is not in the order as they are in the vuex state store
Could someone help me on this
The best way I tried to overcome this problem is to force re-render the v-data-table component, but when I do this I cannot drag and drop anymore
Force rendered using the following the template
<template>
<component-to-re-render :key="componentKey" />
</template>
// script
export default {
data() {
return {
componentKey: 0,
};
},
methods: {
forceRerender() {
this.componentKey += 1;
}
}
}

This might not be the optimal solution, but I had a similar problem except I was just using a regular Array. I managed to fix it by calling the Sortable.create() method in updated() life cycle hook.
My guess is that when you call Sortable.create(table, ...) it refers to that instance of the table element. However, when you try to change the table by modifying the key, it changes that instance. Therefore, you need to call Sortable.create() again whenever the vue component is updated.

Related

ApexCharts & Vue - changing prop values does not update chart in chart component

I have an ApexCharts chart in a separate component, and the series values are passed in as a prop.
My parent component makes some calculations in beforeMount(), which determines the values in the array that is the prop.
I don't know why, but it's not updating dynamically.
ApexCharts documentation says:
You don't actually need to call updateSeries() or updateOptions() manually
And I would expect Vue to update the values like this automatically.
I have checked by displaying the variable passed as a prop in the parent component, and the values are updating after the calculations are made. Do I need to do something extra to 'push' these through to the child component again, after this?
I've found a workaround, be it's still surprising to me that it doesn't update automatically.
From: https://michaelnthiessen.com/force-re-render/
If I assign a key to the component, like this:
<Chart :values='this.values' :key="componentKey" />
export default {
data() {
return {
componentKey: 0,
};
},
methods: {
forceRerender() {
this.componentKey += 1;
}
}
}
And then call the forceRerender() method after I've done my calculations for this.values, everything seems fine -- the chart displays with the correct values from the calculated prop.

How do I fix "Computed property ... was assigned to but it has no setter" error in Buefy b-table component using Vuex store

Situation:
I have a VueJS2 app with an array of items in my Vuex store:
export default new Vuex.Store({
state: {
checkedItems: []
}
...
The idea is to have the checked (selected) items in a buefy b-table component globally available through this array. The b-table is initiated in my component like so:
<b-table
...
:checked-rows.sync="checkedItems"
...
and the store's state is mapped within the component like so:
...
computed: {
...mapState(['checkedItems'])
},
...
Problem:
The rows get selected visually (i.e. the checkbox toggles between checked/ clear) but the checkedItems array of the store does not get updated. I know this because for debugging I display a count for the array and it remains zero no matter how many items I (de-)select. The browser console shows "[Vue warn]: Computed property "checkedFrqs" was assigned to but it has no setter." when I select a row.
I notice however it works when I manually push an entry in one of the components methods viz:
this.checkedItems.push(row)
Question:
How do I get
:checked-rows.sync="checkedItems"
to work seamlessly for the Vuex array? (P.S. when I use a local array instead of the Vuex store's array, everything also works)
Silly me, this solved it:
:checked-rows.sync="$store.state.checkedItems"
(not using the getters->mapState)

Updating the values sent to child component on user click in vuejs

I have two components in mu app.vue and i will send data from app.vue to my first component(filter component) at the time of page load.
Now based on the user actions in the displayed data in the second component i need to pass new vales back to the first component.
There i am using a and a . Consider one of the props i receive in the first component is "nselectedOption" and i do this in data: { return { selectedOption: this.nselectedOption }} to avoid mutation warning.
Now everytime i update the values for this component from second component, i am seeing changes in "nselectedOption" only and not in "selectedOption". Can you explain why is that ?
I need the updated value into a v-model of .
1. If i use "nselectedOption" it is updating the textbox but while editing the value throws error.
2. If i use "selectedOption" it is not updating the values in the textbox itself.
I have even tried using the computed values to return the value, it works but if i try to change values in other options in the filter component the already updated values displays null or nothing.
Please help me. Is this problem can be solved using State Management Concept or do i have to have a separate compoenent other than App.Vue to do all this so that it would act as a parent/child kinda thing or is there anyother way to overcome this.
Try using watcher. If you watch for nselectedOption, everytime it changes, the watcher will fire and bind the changed value to selectedOption.
props: ['nselectedOption'],
data: {
selectedOption
},
watch: {
nselectedOption: function (val) {
this.selectedOption = val
}
}
Also, if the prop you are watching is an object/array, consider using spread operator if you want to make a local copy to avoid mutation.
this.someObj = { ...someProp }

VueJS - Can't assign value from mapState to data property after reloading the page

Can't assign the value from mapState to data property after reloading the page, it works if you go to the child page but not if you are already standing in the child page and reloading the browser.
Computed mapState
computed: {
...mapState({
tsStore: state => state.SchemeStore
})
}
Data Property
data () {
return {
works: '',
offTime: '',
}
}
Mounted
if (this.tsStore.singleView) {
// Set data based on api.
let single = this.tsStore.singleView
this.works = single.works
this.offTime = single.offTime
}
After reloading works and offTime get empty in the data property.
Yes, the problem is the state being updated after the component was mounted;
So, the updated method is called instead of mounted.
It is visible in this fiddle, where the API call is simulated by the setTimeout:
https://jsfiddle.net/eywraw8t/369915/
I think the best way to get the component updated is using computed properties, where Vue implements proxies to watch for changes, like this fiddle:
https://jsfiddle.net/3mn2xgvr/
I moved the changes to a computed properties so when the state in Vuex changes, all data that depends on that changes.

How to force VueJS custom component to re-render itself and all its child component

I have a use case where I have a custom Vue Component that populates its child components dynamically using the JSON. When this top level vue component is created it loads all the children components using the JSON. I have a provision where I can add additional controls on the form when I update the JSON from which it renders itself.
So when I update the JSON on backend using AJAX, I would like re-render everything upon successful post.
Also I came across few articles that say that the regenerating the Form on Custom Vue component should be handled using v-show and/or v-if directive.
This will not fit with my use case.
I looked into forceUpdate API, which is applicable for current component only. It does not affect child components.
So looks like handling forceUpdate on every component is the only way to go in my use case?
Based on the diagram you can see that in the MainFrom component is top level component. Following is the template for the MainForm:
<template>
<div>
<div v-for="(entity, index) of mySchemaChunks >
<FormSection :componentList="entity" />
</div>
</div>
</template>
<script>
export default {
store,
computed: {
mySchemaChunks() {
// returns the chunks from schema (schema is stored in Vuex)
// where each chunks is array (segments of schema)
// Each chunk is a section that has its own list of
// controls.
}
},
methods: {
addNewJsonSchemaNodes() {
// This function will update master Json schema in the backend
// using AJAX which was used to generate the JSON from which
// we generate the MainFrom and all its children
// When App is initialized it prepares the JSON to generate
// MainForm and store that JSON in the Vuex module as schema
// and model object
// I do an AJAX post here which only send me status 200
// This is not enough for me to re-render and generate all
// dynamic component
// May be I should try to get back the JSON after successful
// update of Master JSON in backend ... so that I can update
// my Vuex module schema and model object with new values ...
// And that should do the trick and all components (parent to
// children will be rendered ...????
// Edit: OK.. Now I am getting the data back from AJAX post
// which is now rendering the entire form
}
}
}
</script>
Here is the high level overview of section
<template>
<div>
// Render the list of entity passed to it as property in v-for
// This will add the dynamic Vue components as its children
</div>
</template>
forceUpdate() won't rerender children component UI, but tracked properties will.
In your case. You need to bind the data to component at first. Once ajax response back, you just call Vue.set to update the data bound and it will automatically update the children components