I can post an array of objects in Vue, but I'm having trouble posting a simple indexed array. I'm giving streamlined code because I think the answer lies in plain sight for the experienced.
Here's what I've got so far...
<section v-for="(item, index) in items">
<div>
<button #click.prevent="deleteItem(index)">delete</button>
<input type="text" v-model="item[index]" placeholder="enter your item here">
</div>
</section>
<div>
<button #click.prevent="addItem">add item</button>
</div>
The Vue instance data object so far:
data () {
return {
items: ['']
}
},
What works:
The user can add/delete rows on the form.
Vue DevTools shows me an indexed array with empty fields for each row.
Error messages in the JS console:
I would like to see this in the post...
{ "items": ["item1 input value", "item2 input value"] }
Instead I'm only able to get this because Vue won't react to the input changes...
{ "items": ["", ""] }
For comparison, posting an array of objects works like this:
<section v-for="(item, index) in items">
<div>
<button #click.prevent="deleteItem(index)">delete</button>
<input type="text" v-model="item.color" placeholder="enter color here">
<input type="text" v-model="item.price" placeholder="enter price here">
<input type="text" v-model="item.comment" placeholder="enter comment here">
</div>
</section>
<div>
<button #click.prevent="addItem">add item</button>
</div>
The Vue instance data object:
data () {
return {
items: [{ color: '', price: '', comment: '' }]
}
},
I just received the answer in another forum.
It was so silly... item[index] just needs to be items[index].
Related
Looking for some tips on how to nest objects inside objects using a form. My form currently changes the key and value of an object. However, I'm now wanting a second button to be able to create a child (correct termanology?)form input. below you can see an example. I've spent the morning looking at props but I'm unsure if this is the correct way to go, any suggestions are greatly appriciated
{
"color": "black",
"category": "hue",
"type": "primary",
"code": {
"rgba": [255,255,255,1],
"hex": "#000"
}
},
<form id="app">
<h1>
Title goes here
</h1>
<hr>
<div class="row">
<div class="col-xs-2">
<button type="button" v-on:click="addNewObject" class="btn btn-block btn-success">
(Add +) Parent
</button>
</div>
<div class="col-xs-10 text_info">
Click 'Add +' to add an object
</div>
</div>
<div v-for="(object, index) in objects">
<div class="row">
<div class="col-xs-1">
<label> </label>
<button type="button" v-on:click="removeObject(index)" class="btn btn-rem btn-block btn-danger">
Delete
</button>
<button type="button" v-on:click="addNewChildObject()" class="btn btn-rem btn-block btn-success btn-suc">
add { }
</button>
</div>
<div class="form-group col-xs-7">
<div class="test">
<select v-model="object.type" class="selectBox classic">
<option value="" disabled selected hidden>Choose Datatype</option>
<option v-for="type in types"> {{ type }}</option>
</select>
<input v-model="object.name" :name="'objects[' + index + '][name]'" type="string" class="form-control" placeholder="Enter key">
<input v-model="object.dataValue" :name="'objects[' + index + '][dataValue]'" type="string" class="form-control" placeholder="Enter value">
</div>
</div>
</div>
</div>
<hr>
<div>
<pre v-if="seen">{{ mappedObjects }}</pre>
</div>
<button type="button" class="btn-primary" v-on:click="seen = !seen">{{ seen ? 'Click to Hide the JSON' : 'Click to Show the JSON' }}</button>
</form>
const getDefaultObject = () => ({
name: '',
dataValue: '',
type: ''
})
const app = new Vue({
el: '#app',
computed: {
mappedObjects() {
return this.objects.map(({
name,
dataValue,
type
}) => ({
[name]: dataValue,
type
}))
}
},
props: {
},
data() {
return {
seen: false,
types: ['string', 'character', 'number', 'int', 'floating-point', 'boolean', 'date;'],
objects: []
}
},
methods: {
addNewObject: function() {
this.objects.push(getDefaultObject())
},
removeObject: function(index) {
Vue.delete(this.objects, index);
},
addNewChildObject: function () {
}
}
})
If you want n forms with n children just create a model for it following that same structure and pass props to the form.
parent = {
...props,
children: []
}
child = {
...props
}
If the forms are too complex (or a little complex really), split them in separate components and pass children as props.
If you want to use the same form both in parent and children take a look at slots, they will allow you to create flexible layouts.
I am generating a some checkbox dynamically. Now I need to create v-model dynamic.
<div class="form-group input-group">
<label class="form-group-title">DIETARY PREFERENCES</label>
<p>Please mark appropriate boxes if it applies to you and/or your family</p>
<div class="check-group" v-for="v in alldietry" :key="v">
<input type="checkbox" v-model="userinfo.{{#Here will be the value}}" value="" id="Vegetarian">
<label for="Vegetarian">{{v.title}}</label>
</div>
</div>
into the v-model I have try v-model="userinfo.{{xyz}}" its shows error.
You can't use {{ }} interpolation inside attributes.
The v-model value is a javascript expression, so instead of
v-model="userinfo.{{xyz}}"
you can just do
v-model="userinfo[xyz]"
as you would normally do in javascript when accessing a dynamic property of an object.
To bind dynamic object to model, you need to access to key shared by the model value and the set of data used to display your list.
let vm = new Vue({
el: '#app',
data: {
userinfo: {
0: '',
1: ''
}
},
computed: {
alldietry() {
return [
{
id: 0,
title: 'Title'
},
{
id: 1,
title: 'Title'
}
]
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app" class="form-group input-group">
<label class="form-group-title">DIETARY PREFERENCES</label>
<p>Please mark appropriate boxes if it applies to you and/or your family</p>
<div class="check-group" v-for="(v, index) in alldietry" :key="index">
<input type="checkbox" v-model="userinfo[v.id]" value="" :id="v.id">
<label :for="v.id">{{v.title}}</label>
</div>
{{ userinfo }}
</div>
First question on stack overflow, I apologize if I am asking in the wrong place. New to Vue and been trying for several days to finish a small project. I've simplified it but here it is. I want to be able to enter as many customer names as I need, and then be able to add as many customer's childrens names as I need. So an array of customers with a nested array of children. I can get the customers to add, but I cannot figure out why I cannot push a new element into the children's array. Here is my code.
new Vue ({
el: '#app',
data: function () {
return {
formdata: [],
fields: [{
name: '',
childs: [{
cname: '',
}]
}],
};
},
methods: {
addRow: function() {
this.fields.push({
name: "",
childs: [{
cname:'',
}],
});
},
addChild: function() {
this.child.push({
});
},
},
});
And my html
<div id="app">
<button class="btn btn-success" #click="addRow">Add</button>
<div v-for="field in fields" >
<div class="input-group">
<input type="text" placeholder="Name" class="form-control" v-model="field.name">
</div>
<div v-for="child in field.childs" >
<div class="input-group">
<input type="text" placeholder="Child" class="form-control" v-model="child.cname">
<div class="input-group-btn">
<button class="btn btn-success" #click="addChild">Add</button>
</div>
</div>
</div>
</div>
</div>
Again, the problem is that i can push a new "name" to the fields array, but i cannot push a new child into the fields child array. I have been trying every permutation of child childs field fields etc, trying to find how to reference that array. Any help would be greatly appreciated!
In your addChild method, you need to be accessing the childs property of the relevant field. Currently, you are trying to access the childs property of the Vue instance, which doesn't exist.
You should pass the relevant field to the addChild method like so:
<button class="btn btn-success" #click="addChild(field)">Add</button>
And then update your addChild method to reference the childs array of the field passed in:
addChild: function(field) {
field.childs.push({});
}
So I have 2 blocks of HTML, each containing 2 input fields and when submitting the form, I want to get all values from the inputs, and then create an object from the values...
As of know I've done it with plain vanilla JS and it works as it should, however if feels like to touching the DOM a bit to much, and also are very much depending on a specific DOM struckture, and therefore I was thinking there must be a better way, the VUE way so to speak, however im a bit stuck on how to do this the VUE way, which is why posting the question here in hope of getting some useful tips :)
HTML:
<form novalidate autocomplete="off">
<div class="input-block-container">
<div class="input-block">
<input type="text" placeholder="Insert name" name="name[]" />
<input-effects></input-effects>
</div>
<div class="input-block">
<input type="email" placeholder="Insert email address" name="email[]" />
<input-effects></input-effects>
</div>
</div>
<div class="input-block-container">
<div class="input-block">
<input type="text" placeholder="Insert name" name="name[]" />
<input-effects></input-effects>
</div>
<div class="input-block">
<input type="email" placeholder="Insert email address" name="email[]" />
<input-effects></input-effects>
</div>
</div>
<button class="button button--primary" #click.prevent="sendInvites"><span>Send</span></button>
</form>
JS:
methods: {
createDataObject() {
let emailValues = document.querySelectorAll('input[type="email"]');
emailValues.forEach((email) => {
let name = email.parentNode.parentNode.querySelector('input[type="text"]').value;
if(email.value !== "" && name !== "") {
this.dataObj.push({
email: email.value,
name
});
}
});
return JSON.stringify(this.dataObj);
},
sendInvites() {
const objectToSend = this.createDataObject();
console.log(objectToSend);
//TODO: Methods to send data to server
}
}
You can provide data properties for each of your inputs if you have static content.
data: function() {
return {
name1: '',
email1: '',
name2: '',
email2: ''
}
}
Then use them in your template:
<input type="text" placeholder="Insert name" v-model="name1" />
Access in method by this.name1
Try this
<div id="app">
<h1> Finds </h1>
<div v-for="find in finds">
<input name="name[]" v-model="find.name">
<input name="email[]" v-model="find.email">
</div>
<button #click="addFind">
New Find
</button>
<pre>{{ $data | json }}</pre>
</div>
Vue Component
new Vue({
el: '#app',
data: {
finds: []
},
methods: {
addFind: function () {
this.finds.push({ name: '', email: '' });
}
enter code here
}
});
I'm trying to create a form where I have a select list (fetched from API) and user can add items into a seperate array from this list. New array is also rendered via v-for and uses v-model to edit some additional data.
For example I have a list of goods/services defined beforehand which will be rendered into select option block. Now user can select one of these products and add them to a invoice. After adding (pushed to a new array), user must be able to make some additional changes.
<select class="form-control" v-model="selectedServiceId">
<option v-for="service in services" :value="service._id">{{service.name}}</option>
</select>
<button type="button" class="btn btn-primary" v-on:click="addService">Add</button>
add service method:
addService() {
for (var i = 0; i < this.services.length; i++) {
if (this.services[i]._id == this.selectedServiceId) {
this.services_goods.push(this.services[i])
break;
}
}
}
And now I want to render the list I've pushed into:
<ul>
<li v-for="(item, key) in services_goods">
<span>{{item.name}}</span>
<label for="itemPrice">Price €
<input id="itemPrice" v-model="item.price">
</label>
<label for="itemQty">Quantity
<input type="number" min="1" id="itemQty" v-model="item.quantity">
</label>
<div>
<button type="button" v-on:click="removeService(item._id)">X</button>
</div>
</li>
</ul>
everything is fine up until I add the same item twice and try to modify the price for one of them - it changes price for both.
The reason it changes the price for both is that they are the same object. When you insert an object into an array, the value in the array is a reference to the object. You have two references to the same object.
Each object you insert into the array should be newly created, with contents copied from the selected item.
new Vue({
el: '#app',
data: {
selectedServiceId: null,
services: [{
_id: 1,
price: 1,
quantity: 1,
name: 'First'
},
{
_id: 2,
price: 2,
quantity: 2,
name: 'Second'
}
],
services_goods: []
},
methods: {
addService() {
const foundGood = this.services.find((s) => s._id == this.selectedServiceId);
// Object.assign copies an object's contents
this.services_goods.push(Object.assign({}, foundGood));
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.2.6/vue.min.js"></script>
<div id="app">
<select class="form-control" v-model="selectedServiceId">
<option v-for="service in services" :value="service._id">{{service.name}}</option>
</select>
<button type="button" class="btn btn-primary" v-on:click="addService">Add</button>
<ul>
<li v-for="(item, key) in services_goods">
<span>{{item.name}}</span>
<label for="itemPrice">Price €
<input id="itemPrice" v-model="item.price">
</label>
<label for="itemQty">Quantity
<input type="number" min="1" id="itemQty" v-model="item.quantity">
</label>
<div>
<button type="button" v-on:click="removeService(item._id)">X</button>
</div>
</li>
</ul>
</div>