how to get the updated value when saving in vue - vue.js

In my component I get some props from state like this:
computed: mapGetters({
id: 'downloadId',
pageLimit: 'pageLimit',
pageMaxSize: 'pageMaxSize',
cleaningInterval: 'cleaningInterval'
})
and I bind the property:
<input type="number" v-model.number="pageLimit" id="pageMaxSize" />
Save method:
methods: {
onSave () {
alert('Your data: ' + JSON.stringify(this.pageLimit))
}
}
When a value is entered into the input field and the save button is clicked, this.pageLimit remains the initial value
how do I get the updated value?

There is two issues with your code:
v-model should be used with data only and not with computed. a computed property value in Vue.js can not be changed unless the value or one of the values it depends on has changed.
You can not update the state directly. This is one of vuex rules. To update it you have to use a vuex mutation for that.
So the solution is:
Create a data property called tempPageLimit and bind it to the input using v-model.
In the store, Create a mutation that update the pageLimit with the value of the tempPageLimit and map it to your component using mapMutations.
Execute this mutation inside the onSave method.
look here if you want to read about vuex mutations.

Related

How to use Vue v-model binding in Vuetify components together with computed properties and Vuex?

I'm trying to use v-radio-group in conjunction with computed values from Vuex as described similarly here.
Example codepen of the issue I'm facing is here
Whenever a radio button is clicked, a Vuex mutation is called to save the selected value in the state.
However it can be the case that some validation fails inside the mutation and that therefore the value is not changed in the state as expected.
Regardless of what value ends up in the Vuex state, the radio buttons do not truly reflect the current state.
E.g. in the codepen snippet I'd expect the second option (Option 1) never to show as chosen, as the corresponding state is always 0.
As far as I can see this behavior is not only happening when using v-radio-groups.
It happens with all Vuetify components using v-model and computed getters/setters.
So e.g. Vuetifys v-text-input/v-text-field and v-select also show the same behavior.
To sum it up, my questions are the following:
Why is the second option in my codepen example getting selected even as the corresponding state is different?
How can I achieve the expected result (Having Option 1 never shown as selected, even when it is clicked)?
As far as I know Vuetify keeps its own state in their components like v-radio-group.
To change it you need to send updated props. Then it will react and update its own state.
The trouble is that you are performing validation in a mutation. Which is a bad practice in my opinion.
I will show you how to "block" changing state and update v-radio-group so its own state corresponds to what is actually in your $store.state.radioState.
And I will spend some more time to figure out how to performe it in on mutation ;-)
This is not a perfect solution >> my codepen
Your mutation just updates the state.
// store.js
mutations: {
setRadioState (state, data) {
state.radioState = data;
},
},
Your set method do the validation.
// component
computed: {
chosenOption: {
get () {
return this.$store.state.radioState;
},
set (value) {
if (value !== 1) {
this.$store.commit('setRadioState', value)
} else {
const oldValue = this.$store.state.radioState
this.$store.commit('setRadioState', value)
this.$nextTick(() => {
this.$store.commit('setRadioState', oldValue)
})
}
}
}
}
What happens in the set when it fails validation? You save current state to oldValue, you update state so it corresponds to v-radio-group component. And in the $nextTick you change it right back to oldValue. That way v-radio-group gets updated props and change its state to yours.

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.

vuejs pass model from parent component to children component and allow mutation

Currently I have a vue-multiselect component which requires a v-model.
I want to wrap this component so that I can build one single-select component and one multi-select component.
While working on the single select component I encountered the following warning
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "model"
They are right but in my case I really need to change the value from the parent (like I replace my single-select code with the vue-multiselect code) component and I also do not want this warning.
Here is the code for my component:
Vue.component('single-select', {
props: {
model: {
required: true
}
}
template: '<multiselect\n' +
' v-model="model"\n' +
...>\n' +
...
'</multiselect>'
});
One solution would be to pass a function as a model parameter and return the field from the parent but I really hope for a better solution.
Vue has a shortcut for 2 way binding called .sync modifier.
How it works in your case:
add .sync when you pass model as prop
<single-select :model.sync="..."></single-select>
emit an update:model in the child's input event
Vue.component('single-select', {
props: {
model: {
required: true
}
},
template: `<multiselect :value="model" #input="$emit('update:model', $event)"> </multiselect>`
});
Just give the internal model reference a different name, and the in the Vue component's data function map it manually:
Vue.component('single-select', {
props: {
model: {
required: true
}
},
data: function() {
return {
singleSelectModel: this.model
};
}
template: '<multiselect v-model="singleSelectModel"></multiselect>';
});
This is of course, assuming that you do not want to mutate the parent data, but simply making a copy of model and giving the child component the freedom to change it whenever it wants.
If what you want is to also update the parent data from the child, you will have to look into emitting events from the child and listening in the parent.

How to bind input field and update vuex state at same time

Im coming from a React background and it's simply enough to set your state from a prop and you could call setState({...}) to update the state, so, with vue / vuex, I find it difficult.
To simplify:
Vuex State
name: "Foo bar"
Vuex Action
addName
I can change the state no problem but I need to bind an input field and when change, the state is updated. Think of this as an update form where the user details are already pre-filled and they can change their name.
<input #change="addName(newName) v-model="newName" />
I could add a watch to watch for newName and update the state but, I need to pre-fill the input with the state. Ha! I could use beforeMount() but my state is not loaded as yet.
computed: {
...mapState([
'name'
]),
},
beforeMount() {
// this.newName = this.name
console.log('Mounted') // Shows in console
console.log(this.name) // nothing
}
Name shows in templete <pre>{{ name }}</pre>
Yo can use a computed setter
computed:{
name:{
get: function(){
return store.state.name;
},
set: function(newName){
store.dispatch('addName',newName);
}
}
}
enter code here
And set the v-model to the computed property name in your <input> tag :
<input v-model="name" />
Here is the working jsfiddle