How update nested object array value directly by v-model in VUE? - javascript

I need to update my value which is in JSON thru v-model
{ class: "data.child",
"myform.input1": [true, "<input1 value>"]
}
<input type="text" v-model="<what to put here?>" > //so that directly value can be update in my vue data property JSON mentioned above

Cant do it directly with v-model, unless you want to change your input type to maybe multi select.
If you really want the exact output, can listen onchange event like below.
Or can just use v-model and enter your data as you want...but will need to convert to array.
const jsonData = { class: "data.child",
"myform.input1": [true, "<input1 value>"],
"myform.input2": [true, "<input1 value>"]
}
const App = {
template: `<div>
<input type="text" v-model="data['myform.input2']"/>
<input type="text" #change="update"/>
<p>{{JSON.stringify(data, null, 2)}}</p>
</div>`,
methods: {
update: function(event) {
this.data['myform.input1'] = [true, event.target.value];
}
}
,
data(){
return {data: jsonData}
}
}
new Vue({
render: h => h(App),
}).$mount("#app");
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
</div>

Related

Vue push object into array and make immutable

I'm pretty new to Vue/Javascript so this is probably a super simple answer. I have a component that opens a modal where you can choose a product to add to order. The problem is that I when I modify the price then re-open the modal that all the prices are reset.
How can the pickProduct function be modified so that the changes persist when re-opening the modal?
Codepen
new Vue({
el: '#app',
data: () => ({
orderForm: {
lines: []
},
defaultLine: {
product: null,
price: ''
}
}),
methods: {
pickProduct(product) {
const emptyLine = Object.assign({}, this.defaultLine)
const newProduct = Object.assign({}, product)
Object.assign(emptyLine, newProduct)
newProduct.product = newProduct.id
// this.orderForm.lines.push(newProduct)
this.orderForm.lines = [...this.orderForm.lines, newProduct]
}
}
})
You are using :value in your price input, that doesn't actually change the value for the object you are editing. So this has nothing to do immutability. To actually bind the value for the object, use v-model instead of value.
So change this:
<input type="text" :value="item.price" />
to
<input type="text" v-model="item.price" />
CODEPEN

Getting selected vue value into data return

I'm currently using a vue datepicker which, when a date is selected, shows pickedValue as the value for the selected date in vue developer tools:
<div v-cloak v-if="isScheduledTask">
<datepicker value="" name="pickedValue" id="pickedValue" ></datepicker>
</div>
Trying to set the pickedValue to a variable in my data return (i need the picked value to be submitted with other data here) as a $ref is breaking the page. If I change this to just datepicker.pickedValue then it's undefined. What am I doing wrong here?
data() {
return {
pickedValue: this.$refs.datepicker.pickedValue
}
}
It's very bad pattern, but you have no choice working with library that does not emit ANY events.
DON'T DO IT EVER AGAIN!!!
<datepicker ref="datepicker" #click.native="method"></datepicker>
data() {
return {
value: ''
}
},
methods: {
method() {
this.value = this.$refs.datepicker.pickedValue
},
},
Try to use v-model directive to bind your datepicker to that data property pickedValue as follows :
<div v-cloak v-if="isScheduledTask">
<datepicker value="" name="pickedValue" v-model="pickedValue" ></datepicker>
</div>
script :
data() {
return {
pickedValue: ''
}
}

shared v-model value between child and parent

I have a component which shares v-model same as parent component. The code is like below:
Vue.component('greeting', {
template: '<input type="text" :name="name" v-on:input="updateSearch($event.target.value)"> ' ,
props: ['name'],
methods: {
updateSearch: function(value) {
this.$emit('input', value);
}
}
});
const app = new Vue({
el: '#app',
data: {
name: ''
}
});
<script src="https://unpkg.com/vue#2.6.9/dist/vue.js"></script>
<div id="app">
Child: <greeting v-model="name"></greeting>
<br><br><br>
Main: <input type="text" v-model="name" placeholder="" />
</div>
I want to update both input boxes if the user enters text in either of them. Any suggestions would be helpful.
If you pass in a reference like an object as prop, you can bind a property of that object on both your parent and child
Vue.component('greeting', {
template: '<input type="text" v-model="name.value" />' ,
props: ['name']
});
const app = new Vue({
el: '#app',
data: {
name: { value: '' }
}
});
<script src="https://unpkg.com/vue#2.6.9/dist/vue.js"></script>
<div id="app">
Child: <greeting v-bind:name="name"></greeting>
<br><br><br>
Main: <input type="text" v-model="name.value" placeholder="" />
</div>
Usually is a bad practice change props inside child component. In this case, you can create two different variables and update the other one when some of them changes it value (via events and props).
So, greeting component would $emit some event which you will catch inside main component and update main's name
On the other hand, main component would pass a prop to greeting which will be reactive considering changes inside main and will update variable name inside greeting's data.
If you get more cases like that, think about using vuex
I think, what you are looking for is .sync modifier for events in Vue.js 2.3.0+.
You can find a sample implementation of the same in my article here.

Vue JS form issue - mutating vuex store state outside handlers

I am currently getting the [vuex] Do not mutate vuex store state outside mutation handlers error only when I try to edit the form, if I am posting a new plugin it works fine. From this doc I'm not sure where I'm going wrong - while I fetch the plugin from vuex, I try to give the local state those values and then leave vuex alone. Ideally once fetched vuex, I wouldn't need to touch it again until the form is submitted. But I'm not sure what is causing the error exactly
<template>
<div>
<h4>{{this.$route.query.mode==="new"?"New":"Edit"}} Plugin</h4>
<form class="">
<label>Id</label>
<input :value="plugin.id" class="" type="text" #input="updateId">
<label>Name</label>
<input :value="plugin.name" class="" type="text" #input="updateName">
<label>Description</label>
<textarea :value="plugin.description" class="" type="text" #input="updateDescription"></textarea>
<label>Version</label>
<input :value="plugin.version" class="" type="text" #input="updateVersion">
<button type="submit" #click.prevent="submitForm">Submit</button>
</form>
</div>
</template>
<script>
import util from '~/assets/js/util'
export default {
created() {
if (this.mode === 'edit') {
this.plugin = this.$store.state.currentLicence.associatedPlugins.find(p => p.pluginId === this.$route.query.pluginId)
}
},
methods: {
updateId(v) {
this.plugin.id = v.target.value
},
updateName(v) {
this.plugin.name = v.target.value
},
updateDescription(v) {
this.plugin.description = v.target.value
},
updateVersion(v) {
this.plugin.version = v.target.value
}
},
computed: {
mode() { return this.$route.query.mode }
},
data: () => ({
plugin: {
id: null,
name: null,
description: null,
version: null
}
})
}
</script>
Thanks for any help, clearly my understanding of the way that vuex and local state are handled is flawed
You are getting this error because you are editing the state directly.
this.plugin = this.$store.state.currentLicence.associatedPlugins.find(p => p.pluginId === this.$route.query.pluginId) - this is exactly this part of code where you put the object from the store directly into the data, therefore by editing the field you are directly editing the state. Don't do that!
You should always use stuff like (I am not sure how nested computed will work but I don't think you have to nest it):
computed: {
plugin: {
id: {
get () { // get it from store }
set (value) { // dispatch the mutation with the new data }
}
}
}
There is a nice package whill will do most work for you: https://github.com/maoberlehner/vuex-map-fields . You can use it to semi-automatic generate computed with getters and setters for each field.

Vuex input with v-model not reactive

I try to explain it as simple as possible. I have something like this. Simple Vue root, Vuex store and input with v-model inside navbar id.
That input is not reactive... Why?!
HTML
<div id="navbar">
<h2>#{{ test }}</h2>
<input v-model="test" />
</div>
store.js
import Vuex from 'vuex'
export const store = new Vuex.Store({
state: {
test: 'test'
},
getters: {
test (state) {
return state.test
}
}
})
Vue Root
import { store } from './app-store.js'
new Vue({
el: '#navbar',
store,
computed: {
test () {
return this.$store.getters.test
}
}
})
You're binding to a computed property. In order to set a value on a computed property you need to write get and set methods.
computed:{
test:{
get(){ return this.$store.getters.test; },
set( value ){ this.$store.commit("TEST_COMMIT", value );}
}
}
And in your store
mutations:{
TEST_COMMIT( state, payload ){
state.test=payload;
}
}
Now when you change the value of the input bound to test, it will trigger a commit to the store, which updates its state.
You don't want to use v-model for that. Instead, use #input="test" in your input field and in the your methods hook:
test(e){
this.$store.dispatch('setTest', e.target.value)
}
Inside your Vuex store:
In mutations:
setTest(state, payload){
state.test = payload
},
In actions:
setTest: (context,val) => {context.commit('setTest', val)},
The input should now be reactive and you should see the result in #{{test}}
Here is an example of how I handle user input with Vuex: http://codepen.io/anon/pen/gmROQq
You can easily use v-model with Vuex (with actions/mutations firing on each change) by using my library:
https://github.com/yarsky-tgz/vuex-dot
<template>
<form>
<input v-model="name"/>
<input v-model="email"/>
</form>
</template>
<script>
import { takeState } from 'vuex-dot';
export default {
computed: {
...takeState('user')
.expose(['name', 'email'])
.commit('editUser') // payload example: { name: 'Peter'}
.map()
}
}
</script>
The computed property is one-way. If you want two-way binding, make a setter as the other answers suggest or use the data property instead.
import { store } from './app-store.js'
new Vue({
el: '#navbar',
store,
// computed: {
// test() {
// return this.$store.getters.test;
// }
// }
data: function() {
return { test: this.$store.getters.test };
}
});
But a setter is better to validate input value.

Categories