v-model not working with javascript functions - javascript

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>

Related

Passing object with Vue router

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
}
]

Dynamic generated form with checkbox in Vue

I have dynamic generated form in Vue. Every loop have v-model. Everything work fine. But when I use checkboxes v-model work for all loops not on one like in input type text. Can You help me solved this problem? Below Vue code:
<fieldset>
<div class="form-row mb-2" v-for="input, index in journal" :key="index">
<div class="col-auto">
<label for="date">Data</label>
<Datepicker v-model="input.date" input-class="form-control" :input-attr="{id: 'date', name: 'date'}" style="width: 100%;" />
</div>
<div class="col-md-2">
<label for="timeStart">Od</label>
<Datepicker type="time" v-model="input.timeStart" format="HH:mm" input-class="form-control" :input-attr="{id: 'timeStart', name: 'timeStart'}" style="width: 100%;" />
</div>
<div class="col-md-2">
<label for="timeEnd">Do</label>
<Datepicker type="time" v-model="input.timeEnd" format="HH:mm" input-class="form-control" :input-attr="{id: 'timeEnd', name: 'timeEnd'}" style="width: 100%;" />
</div>
<div class="col-md-2">
<label for="players">Lista obecności</label>
<div class="form-check" v-for="item in input.players">
<input v-model="item.checked" type="checkbox" class="form-check-input" :id="'id-'+item.id+'set'+index">
<label class="form-check-label" :for="'id-'+item.id+'set'+index">{{ item.fullName }}</label>
</div>
</div>
<div class="col-auto">
<label for="description">Opis</label>
<textarea v-model="input.description" class="form-control" rows="7" id="description" placeholder="Opis"></textarea>
</div>
<div class="col-auto" #click="addInput" v-show="index == journal.length-1 && journal.length < 16">
<ButtonVue style="margin-top: 30px;" title="Dodaj" type="button" cancelWidth="true" color="btn-success"><i class="fas fa-plus"></i></ButtonVue>
</div>
<div class="col-auto align-self-start" #click="removeInput(index)" v-show="index || ( !index && journal.length > 1)">
<ButtonVue style="margin-top: 30px;" title="Usuń" type="button" cancelWidth="true" color="btn-danger"><i class="fas fa-minus"></i></ButtonVue>
</div>
</div>
</fieldset>
 
data() {
return {
contact: [],
journal: [{
date: "",
timeStart: "",
timeEnd: "",
players: "",
description: ""
}],
contacts: [],
}
},
Methods:
Method for creating dynamic form
addInput() {
this.journal.push({
date: "",
timeStart: "",
timeEnd: "",
players: this.contact,
description: ""
});
},
And here is the method which gets players from contacts
getContacts() {
this.pageLoader = true;
this.$http.get('/pkpar/get-contacts')
.then(({
data
}) => {
this.contacts = data.contacts;
for(let i=0; i<this.contacts.length; i++)
{
this.contact.push({'id': this.contacts[i]['id'], 'fullName' :
this.contacts[i]['fullName'], 'checked': true});
}
this.journal[0].players = this.contact;
this.pageLoader = false;
})
.catch(error => {
console.log(error);
});
},
Your addInput method creates and pushes new object into journal array, but each object created this way has a players property which references same array (this.contact)
The Difference Between Values and References in JavaScript
Easiest (but not most optimal) way to handle this is to create a copy of the array and objects inside for each new journal:
addInput() {
this.journal.push({
date: "",
timeStart: "",
timeEnd: "",
players: this.contact.map((player) => ({ ...player })),
description: ""
});
},

How to append input elements dynamically in vue

I'm trying to append new input fields based on a condition, I will describe the workflow to help you understand
First stage is to press this button to implement 2 functions(1 is to move to other fieldset in the staged form, second function is to append the inputs:
<input type="button" name="secondBtn" class="next action-button" value="Next" id="secondBtn" #click="nextPlusappend"/>
nextPlusappend:
nextPlusappend() {
this.isNextClicked();
this.appendFields();
}
appendFields:
//this.platform initllized as 'one' so the condition is true.
if(this.platform === 'one'){
this.inputFields.push({
Username: '',
Password: '',
AffiliateID: '',
CI: '',
GI: '',
})
}
And I want to append all the fields from the function to this fieldset:
<div v-if="currentPage === 2">
<fieldset id="fieldset3" v-for="(param, index) in inputFields" :key="index">
<h2 class="fs-title">API Credentials</h2>
<h3 class="fs-subtitle">Step 3- Add any parameter for the integration</h3>
<input v-model="param.Username" type="text" name="`inputFields[${index}[Username]]`" placeholder="userName">
<input type="button" name="previous" class="previous action-button" value="Previous" #click="isPreviousClicked"/>
<input type="submit" name="submit" class="submit action-button" value="Create a Ticket" id="excel"/>
</fieldset>
</div>
How can I append this without hard code all the input fields as I did here:?
<input v-model="param.Username" type="text" name="`inputFields[${index}[Username]]`" placeholder="userName">
This is designated to be dynamic, what do i mean?
I mean that if the this.platform is equal to "one" there will be a unique fields, and if this.platform equal to "two" for example there will be other unique fields.
Don't think like "pushing a form field", rather think like "adding a new item to the dataset" (and of course, its displayed UI is a form field).
Let me give an example:
Vue.component("FormField", {
props: ["label", "value"],
computed: {
val: {
get() {
return this.value
},
set(val) {
this.$emit("update:value", val)
}
},
},
methods: {
handleClickAdd() {
this.$emit("click-add-field")
}
},
template: `
<div>
<label>
{{ label }}: <input type="text" v-model="val" />
</label>
<button
#click="handleClickAdd"
>
+ ADD
</button>
</div>
`,
})
new Vue({
el: "#app",
data() {
return {
formFields: [{
label: "Field 1",
value: null,
}],
}
},
methods: {
handleClickAddField() {
const item = {
label: `Field ${ this.formFields.length + 1 }`,
value: null,
}
this.formFields = [...this.formFields, item]
},
},
template: `
<div
class="container"
>
<div
class="col"
>
<h4>FIELDS:</h4>
<hr>
<form-field
v-for="(field, i) in formFields"
:key="i"
:label="field.label"
:value.sync="field.value"
#click-add-field="handleClickAddField"
/>
</div>
<div
class="col"
>
<h4>FIELD VALUES:</h4>
<hr>
<div
v-for="(field, i) in formFields"
:key="i"
>{{ field.label }}: {{ field.value }}</div>
</div>
</div>
`,
})
.container {
display: flex;
}
.col {
padding: 0 8px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>
You can see, that on ADD I just added a new item in the formFields - the values are bound in the template to a child-component, that handles the actual representation of the fields.
On the right side of the snippet, you can see another benefit of decoupling data from UI: I created another representation of the same data source - that immediately reacts to any changes!

VueJS = Uncaught TypeError: Cannot read property 'settings' of undefined

I have a basic input that should update a data on input change, but it doesn't because it returns Uncaught TypeError: Cannot read property 'settings' of undefined
Vue component
<template>
<div>
<div class="inner_container">
<p>
URL:
<span>{{settings.url}}</span>
</p>
<div class="input_row">
<input
class="input_text"
id="getURL"
type="url"
inputmode="url"
placeholder="Enter URL"
title="URL"
#input="changeUrl"
/>
<label class="label_" for="getURL">URL Link</label>
</div>
<button class="button" #click="saveSettings">Save all Values</button>
</div>
<div>
</template>
<script>
import axios from "axios";
import _ from "lodash";
export default {
name: "Home",
data() {
return {
settings: {
brightness: "",
},
};
},
methods: {
changeUrl: _.debounce((e) => {
this.settings.url = e.target.value;
}, 500),
},
};
</script>
On each input change I receive the above error.
What am I doing wrong ?
The problem is that this in the arrow function is not referring to the object you want. One solution is to use a normal function and predefine the property url in settings:
new Vue({
el: '#app',
data() {
return {
settings: {
brightness: "",
url: ""
},
};
},
methods: {
changeUrl: _.debounce(function(e) {
this.settings.url = e.target.value;
}, 500),
saveSettings(){
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.19/lodash.min.js"></script>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<div id="app">
<div class="inner_container">
<p>
URL: <span>{{settings.url}}</span>
</p>
<div class="input_row">
<input
class="input_text"
id="getURL"
type="url"
inputmode="url"
placeholder="Enter URL"
title="URL"
#input="changeUrl"
/>
<label class="label_" for="getURL">URL Link</label>
</div>
<button class="button" #click="saveSettings">Save all Values</button>
</div>
</div>
A simpler approach you may find useful is to set the variable using v-model:
new Vue({
el: '#app',
data() {
return {
settings: {
brightness: "",
},
};
},
methods: {
saveSettings(){
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.19/lodash.min.js"></script>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<div id="app">
<div class="inner_container">
<p>
URL: <span>{{settings.url}}</span>
</p>
<div class="input_row">
<input
class="input_text"
id="getURL"
type="url"
inputmode="url"
placeholder="Enter URL"
title="URL"
v-model="settings.url"
/>
<label class="label_" for="getURL">URL Link</label>
</div>
<button class="button" #click="saveSettings">Save all Values</button>
</div>
</div>
Ciao, try to use debounce like this:
_.debounce(function(e) {
this.settings.url = e.target.value;
}, 500)
The problem is that you are using this in a statement that is not being called on a JS class. Fix this by changing the this to a variable name, and setting that variable name to a class.

vue form e.target.name.value is undefined

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>

Categories