My values on my vue js form are blank or undefined when i submit them for some reason. I am trying to log e.target.name.value to the console to check my form values.
Is there an easier way to do this in vue for this setup? I've been trying different methods and I fear i'm trying to homogenize my vanilla js with vue and creating more problems for myself.
my vue data:
new Vue({
el: '#grocery_list',
data: {
selected: null,
list: [
{
id: 0,
category: 'Baked goods',
food: ['bread','cookie','butter','powder']
},
{
id: 1,
category: 'meats',
food: ['chicken','turkey','beef']
},
{
id: 2,
category: 'fruits',
food: ['bannana','apple','pineapple']
},
{
id: 3,
category: 'canned goods',
food: ['tomatoes','green beans','corn']
},
{
id: 4,
category: 'veggies',
food: ['broccoli','celery','lettuce']
},
{
id: 5,
category: 'pantry',
food: ['broom','mop','dried beans']
},
],
isHidden: true,
form: {},
},
methods:{
addItem: function(e){
console.log(form)
},
viewItemsinCat: function(){
this.isHidden = false
},
checkItem: function(){
}
}
})
my html
<div class="addItem" id="addItem" #submit.prevent="addItem">
<form>
<label for="addItem">Add food item</label>
<input v-model="form.foodName" type="text" name="foodName"></input>
<div>
<select v-model="form.category" id="food">
<option v-for="item in list" name="item">{{item.category}}</option>
</select>
</div>
<div>
<button type="submit">Add Item</button>
</div>
</form>
</div>
In vuejs you don't have to use the names or ids to get value of an input all you have is to use v-model which is reactive and will update all the form values instantly
check this out
<template>
<div class="addItem" id="addItem" #submit.prevent="addItem">
<form>
<label for="addItem">Add food item</label>
<input v-model="form.foodName" type="text" name="foodName"></input>
<div>
<select v-model="form.category" id="food">
<option v-for="item in list" name="item">{{item.category}}</option>
</select>
</div>
<div>
<button type="submit">Add Item</button>
</div>
</form>
</div>
</template>
<script>
export default {
data: () => ({
form: {}
}),
methods: {
addItem: function(){
console.log(this.form)
}
}
}
</script>
Related
I'm trying to make an edit button for an object(song). I want to pass my data to the edit form, so the input it will be completed with the actual data, but I always get undefined. I tried a lot of solutions but no one worked for me. What's the problem?
My Song Component, I am trying to pass its data to the edit form
<template>
<div class="hello">
<h1>{{ song.name }}</h1>
<p>Author: {{ song.author }}</p>
<p>Views: {{ song.views }}</p>
<!-- <button #click="$router.push('/update-song?id=' + song.id )">Update</button> -->
<button #click="$router.push({path: '/update-song', Component: UpdateSong, props: {song: song}})">Update</button>
</div>
</template>
<script>
export default {
name: 'Song',
props: {
song: Object
}
}
</script>
My edit view:
<template>
<div>
<p>Update a song: {{this.author}} - {{this.name}}</p>
<input type="text" id="name" placeholder="Name" v-model="name"/><br/>
<input type="text" id="author" placeholder="Author" v-model="author"/><br/>
<input type="text" id="country" placeholder="Country" v-model="country"/><br/>
<input type="text" id="duration" placeholder="Duration" v-model="duration"/><br/>
<input type="text" id="views" placeholder="Views" v-model="views"/><br/>
<input type="text" id="genre" placeholder="Genre" v-model="genre"/><br/>
<button #click="updateSong">Update Song</button>
</div>
</template>
<script>
export default{
name: 'UpdateSong',
props: {
song: Object
},
mounted() {
console.log(this.song) //undefined
},
data(){
return{
name: '',
author: '',
country: '',
duration: 0,
views: 0,
genre: ''
}
},
methods: {
updateSong(){...}
}
}
</script>
My routes:
const routes = [...,
{
path: '/update-song',
name: "updateSong",
component: UpdateSong
}
]
I am new to Vue JS and have been learning it from the documentation provided. My project is a simple task adding web-app. On using the v-model directive, I'm not getting any output. My javascript function to add the task is apparently not being called.
<template>
<div id="text">
TASKS:
<form onsubmit="return addTodo()">
<input type="text" class="todo-input" placeholder="What's up" v-model="message">
<input type="date" class="todo-input" v-model="ddate" >
<input type="submit" value="Add">
</form>
<div v-for="(todo, index) in todos" :key="todo.id" class="todo-item">
<div>
{{todo.id}}{{todo.title}}{{todo.date}}
</div>
</div>
</div>
</div>
</template>
export default {
name: 'todo-list',
data () {
return {
message: '',
ddate: '',
idForTodo: 1,
todos: [
]
}
},
methods: {
addTodo(){
if(this.message.trim().length == 0){
return
}
this.todos.push({
id: this.idForTodo,
title: this.message,
completed: false,
editing: false,
date: this.ddate,
})
this.ddate = ''
this.message = ''
this.idForTodo++
},
}
}
Looks like someone edited the question with correct code while I was writing the answer. I tried and tested same code in code snippet and it's working.
const app = new Vue({
el: '#text',
data() {
return {
message: '',
ddate: '',
idForTodo: 1,
todos: [
]
}
},
methods: {
addTodo(){
console.log(this.message)
if(this.message.trim().length == 0){
return
}
this.todos.push({
id: this.idForTodo,
title: this.message,
completed: false,
editing: false,
date: this.ddate,
})
this.ddate = ''
this.message = ''
this.idForTodo++
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.0/vue.js"></script>
<div id="text">
TASKS:
<form>
<input type="text" class="todo-input" placeholder="What's up" v-model="message">
<input type="date" class="todo-input" v-model="ddate" >
<button v-on:click.prevent="addTodo">Add</button>
</form>
<div v-for="(todo, index) in todos" :key="todo.id" class="todo-item">
<div>
{{todo.id}} {{todo.title}} {{todo.date}}
</div>
</div>
</div>
I have like this template currently:
<div>
<div v-for="(item, key) in items" :key="key">
<div>
<input type="text" :value="item.title">
</div>
<div>
<input type="text" :value="item.description">
</div>
<div class="actions">
<button type="button" #click="discardChanges(item)" :disabled="!itemChanged">Discard changes</button>
<button type="button" #click="sendChanges(item)" :disabled="!itemChanged">Save</button>
</div>
</div>
</div>
<script type="text/javascript">
export default {
data() {
return {
itemChanged: false,
items: [
{
title: "Apple",
description: "The bigger company of the world"
},
{
title: "Amazon",
description: "The bigger online store of the USA"
},
]
}
},
methods: {
sendChanges(item) {
// Send API request to update item
},
discardChanges(item) {
// Set old value if item changed
}
}
}
</script>
In this case I generate dynamic inputs from array of items. I need to correctly control my action buttons by detecting current item changes.
For example user will change second item title and will click to Discard changes button. In this case how I can set old value to input?
Also how I can correctly disable or enable action buttons by comparing ch
I have made use of another array called oldValues and modified the methods accordingly. Also I suggest you to use v-model instead of :value
<div>
<div v-for="(item, key) in items" :key="key">
<div>
<input type="text" v-model="item.title">
</div>
<div>
<input type="text" v-model="item.description">
</div>
<div class="actions">
<button type="button" #click="discardChanges(key)" :disabled="!itemChanged">Discard changes</button>
<button type="button" #click="sendChanges(item, key)" :disabled="!itemChanged">Save</button>
</div>
</div>
</div>
<script type="text/javascript">
export default {
data() {
return {
itemChanged: false,
oldValues: [
{
title: "Apple",
description: "The bigger company of the world"
},
{
title: "Amazon",
description: "The bigger online store of the USA"
},
],
items: [
{
title: "Apple",
description: "The bigger company of the world"
},
{
title: "Amazon",
description: "The bigger online store of the USA"
},
]
}
},
methods: {
sendChanges(item) {
// Send API request to update item
this.oldValues[key]=item;
},
discardChanges(item) {
// Set old value if item changed
this.items[key]=this.oldValues[key];
}
}
}
</script>
How can I render and show nested elements on the UI (from nested value[] field of object) which are generated dynamically when you select option (e.g. List) in parent element?
For example, I got this code below. When you create field and chose List option, you should see one more nested and so on, depth is unknown. How can I render this to show to user? Kind of v-for inside v-for doesnt seem to work. Maybe I need recursion here, but I dont know how to release it.
I appreciate any help!
var app = new Vue({
el: '.container',
data: {
modelname: '',
fields: []
},
methods: {
addNewField() {
this.fields.push({
left: 0,
type:'',
method:'',
size:'',
value:''}
)
},
createChildElement(field) {
if (field.type == "List") {
Vue.set(field, "value", []);
field.value.push({
type:'',
left: field.left+20,
method:'',
size:'',
value:''}
);
}
},
showJson() {
const data = this.fields
alert(JSON.stringify(data, null, 2));
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div class="container">
<h1 class="font-italic text-warning">TDGT Web Client</h1>
<!--<button id="add-model" class="btn btn-warning" #click="addNewModel">Создать модель</button>-->
<div>
<button id="add-field" class="btn btn-sm btn-warning" #click="addNewField">Create field</button>
<button id="show-json" class="btn btn-sm btn-warning" #click="showJson">Show JSON</button>
<div v-for="(field, index) in fields" :style="{marginLeft: field.left+'px'}" :key="index">
<ul>
<li>
<select v-model="field.type" v-on:change="createChildElement(field)" aria-label="Выбрать тип поля">
<option selected>Тип поля</option>
<option value="List">List</option>
<option value="Map">Map</option>
<option value="Integer">Integer</option>
</select>
<select v-model="field.method" v-if="field.type === 'Map' || field.type === 'List'" aria-label="Метод генерации">
<option selected>Тип значения</option>
<option value="Static">Static</option>
<option value="Random">Random</option>
<option value="Range">Range</option>
</select>
<input type="text" v-if="field.type === 'Map' || field.type === 'List'" v-model="field.size" placeholder="Размерность">
<input type="text" v-if="field.type === 'Integer'" v-model="field.value" placeholder="Значение">
</li>
<ul></ul>
</ul>
</div>
</div>
</div>
UPD. Based on answers I tried to make a solution for my task but I still have some problems. I moved most of the code to component, but I receive a lot of errors which I cant resolve. e.g.:
Invalid prop: type check failed for prop "item". Expected Object, got Array.
Property or method "fields" is not defined on the instance but referenced during render.
Here is my code:
Vue.component("el-inpt-group", {
template: "#item-template",
props: {
item: Object,
}
});
var app = new Vue({
el: '.container',
data: {
modelname: '',
fields: [
]
},
methods: {
addNewField() {
this.fields.push({
name: '',
left: 0,
type:'',
method:'',
size:'',
value:''}
)
},
createChildElement(field) {
if (field.type == "List") {
Vue.set(field, "value", []);
field.value.push({
name: '',
type:'',
left: field.left+20,
method:'',
size:'',
value:''}
)
}
},
showJson() {
const data = this.fields
alert(JSON.stringify(data, null, 2));
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script type="text/x-template" id="item-template">
<ul>
<li v-for="field in fields">
<input type="text" v-model="field.name" placeholder="Name">
<select v-model="field.type" v-on:change="createChildElement(field)" aria-label="Выбрать тип поля">
<option selected>Тип поля</option>
<option value="List">List</option>
<option value="Map">Map</option>
<option value="Integer">Integer</option>
</select>
<select v-model="field.method" v-if="field.type === 'Map' || field.type === 'List'" aria-label="Метод генерации">
<option selected>Тип значения</option>
<option value="Static">Static</option>
<option value="Random">Random</option>
<option value="Range">Range</option>
</select>
<input type="text" v-if="field.type === 'Map' || field.type === 'List'" v-model="field.size" placeholder="Размерность">
<input type="text" v-if="field.type === 'Integer'" v-model="field.value" placeholder="Значение">
</li>
<ul><el-inpt-group v-for="child in fields.value" :style="{marginLeft: field.left+'px'}" :key="child.name" :item="child"></el-inpt-group></ul>
</ul>
</script>
</head>
<body>
<div class="container">
<h1 class="font-italic text-warning">TDGT Web Client</h1>
<button id="add-field" class="btn btn-sm btn-warning" #click="addNewField">Create field</button>
<button id="show-json" class="btn btn-sm btn-warning" #click="showJson">Show JSON</button>
<el-inpt-group :item="fields"></el-inpt-group>
</div>
</div>
Indeed recursion is your solution here.
When you can't see how to organise your code properly, often that means you haven't divided your code into enough components.
To make a simple example, just create a component that takes one item as a property, and then call itself when this item as sub items.
Given this example structure:
[
{
name: 'Todo 1'
},
{
name: 'Todo 2',
items: [
{
name: 'Todo 2.1'
},
{
name: 'Todo 2.2'
}
],
},
{
name: 'Todo 3',
items: []
},
]
<template>
<div>
<article v-for="subTodos of todo.items" :key="subTodos.name">
<h1>{{ subTodos.name }}</h1>
<Todo :todo="subTodos" />
</article>
</div>
</template>
<script>
export default {
name: 'Todo',
props: {
todo: { type: Object, required: true }
}
}
</script>
<template>
<Todo :todo="firstItem" />
</template>
<script>
export default {
data () {
return {
firstItem: { name: 'First todo', items: nestedTodos }
}
}
}
</script>
Here, as long as todo.items isn't an empty array, it will create a <Todo> component, which himself creates more <Todo> elements whenever they have items themselves...
I have users with their own checkboxes, I need to do so that when you select a specific user by clicking on the checkbox, then when you click on the "Get user id" button, get the user ID in the getUserId method.
Here is the code in CodeSandbox
<template>
<div>
<div class="user" v-for="(user, i) in items" :key="i">
<p>{{ user.name }}</p>
<p>{{ user.age }}</p>
<input type="checkbox" />
</div>
<button #click="getUserId()">Get user id</button>
</div>
</template>
<script>
export default {
methods: {
getUserId() {},
},
data() {
return {
items: [
{
id: 1,
name: "Alex",
age: 23,
},
{
id: 2,
name: "Robert",
age: 33,
},
{
id: 3,
name: "Jacob",
age: 55,
},
],
};
},
};
</script>
Seems you want to collect the checked user IDs. To do so, you should bind your checkbox models to an array and set the value to the user.id
new Vue({
el: "#app",
methods: {
getUserId() {
console.log("userIds", this.userIds)
},
},
data() {
return {
items: [{"id":1,"name":"Alex","age":23},{"id":2,"name":"Robert","age":33},{"id":3,"name":"Jacob","age":55}],
userIds: [] // start with an empty array
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<!-- Note: the `user.id` makes for a much better `key` -->
<div class="user" v-for="user in items" :key="user.id">
<p>{{ user.name }}</p>
<p>{{ user.age }}</p>
<!-- Set the checkbox value to `user.id` and bind the model to your array -->
<input type="checkbox" :value="user.id" v-model="userIds" />
</div>
<button #click="getUserId()">Get user id</button>
</div>
See https://v2.vuejs.org/v2/guide/forms.html#Checkbox