Vue JS push items to array? - vue.js

I would like to push the input to the array. When I press the button to add the items nothing happens. I've searched multiple websites but it seems that I am too dumb to find the right code :(
Do anyone know whats the problem with the code:
<!DOCTYPE html>
<head>
<title>Clientseitige Webentwicklung mit Vue.js</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app_basic">
<ul>
<li v-for="value in cars">{{ value }}</li>
</ul>
<input id="input1" type="text" v-model="newFarbe" placeholder="farbe">
<input id="input2" type="text" v-model="newMarke" placeholder="marke">
<input id="input3" type="text" v-model="newPS" placeholder="ps">
<button v-on:click="addCar">Hinzufügen</button>
</div>
<script>
var app_basic= new Vue(
{
el: '#app_basic',
data: {
cars:{
farbe: 'Blau',
marke: 'Ford',
ps: '240'
}
},
methods:{
addCar: function() {
this.cars.push({farbe : this.newFarbe, marke : this.newMarke, ps : this.newPS});
this.newFarbe='';
this.newMarke='';
this.newPS='';
}
}
});
</script>
</body>
</html>

cars should be an array and the inputs models should be defined in data. Moreover, it's better to have some sort of validation before the insertion:
new Vue({
el: '#app_basic',
data: {
cars: [
{
farbe: 'Blau',
marke: 'Ford',
ps: '240'
}
],
newFarbe: '',
newMarke: '',
newPS: ''
},
methods:{
addCar: function() {
if(!this.newFarbe || !this.newMarke || this.newPS) return;
this.cars.push({
farbe : this.newFarbe, marke : this.newMarke, ps : this.newPS
});
this.newFarbe='';
this.newMarke='';
this.newPS='';
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app_basic">
<ul>
<li v-for="value in cars">
{{ value.farbe }} -
{{ value.marke }} -
{{ value.ps }}
</li>
</ul>
<input id="input1" type="text" v-model="newFarbe" placeholder="farbe">
<input id="input2" type="text" v-model="newMarke" placeholder="marke">
<input id="input3" type="text" v-model="newPS" placeholder="ps">
<button v-on:click="addCar">Hinzufügen</button>
</div>

Related

How can I add a task to a list in my Vue 2 to-do app?

I am trying to add a task to a tasklist in Vue based on the input and add task button, but I keep getting the error "taskList is not defined". Does anybody see how to fix this problem? The code is as following:
<template>
<div id="input">
<form>
<input v-model="task.name">
<button v-on:click="addTask" v-bind:value="task.name">+</button>
</form>
<ol>
<div v-for="task in taskList" :key="task.id">
{{ task.name }}
<div v-if="task.completed">
<h2> Done </h2>
</div>
<div v-else>
<h2> Not done</h2>
</div>
</div>
</ol>
</div>
</template>
<script>
export default {
name: 'AddTask',
data: function() {
return {
taskList: [
{
name: 'task', completed: false, id: 3
}
] }
},
methods: {
addTask: function (task) {
taskList.push(task);
alert('test');
}
}
}
</script>
Ps. any other Vue tips are welcome as well.
You need to separate out your taskList and the current task you're adding, decouple it as a new object, then add it to your taskList array.
When referring to items in your data object you need to use the this keyword – e.g this.taskList rather than taskList:
new Vue({
el: "#app",
data: {
id:1,
taskList: [],
currentTask:{
completed:false,
name:'',
id:this.id
}
},
methods: {
addTask: function() {
let newTask = {
completed:this.currentTask.completed,
name:this.currentTask.name,
id:this.currentTask.id
}
this.taskList.push(newTask);
this.id++;
//alert('test');
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div id="input">
<ol>
<li v-for="task in taskList" :key="task.id">
{{ task.name }}
<input type="checkbox"
:checked="task.completed"
#change="task.completed = !task.completed">
<span v-if="task.completed">
Done
</span>
<span v-else>
Not Done
</span>
</li>
</ol>
<input type="text" v-model="currentTask.name">
<button v-on:click="addTask">+</button>
</div>
</div>
From what I see in your template you use tasklist but you define it as taskList You will want to make sure your names are in the same case. Usually you'll see camelCase in vue, but other popular ones are snake_case and PascalCase

How can I add Vue.js search filter

I try to learn Vue.js and have now tried to solve a filter search of my array savedMembers. But I can not make it work.
Array name: savedMembers
variables in array, firstName, lastName and email
search field: search
How can I add responsive search?
How can I update view with saved members?
I would like a filter function to filter all values of array. But it´s okey if I only can filter by firstname.
This is my index.html
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="style.css">
<title>Team Page</title>
</head>
<body>
<div id="app">
<team-page></team-page>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2/dist/vue.js"></script>
<script src="main.js"></script>
</body>
</html>
This is my main.js
template: `
<div class="team_members">
<h3>Team</h3>
<div class="create_member">
<form action="" #submit.prevent="onSubmit">
<label for="firstName">First name</label><br>
<input type="text" v-model="firstName" name="firstName"><br>
<label for="lasttName">Last name</label><br>
<input type="text" v-model="lastName" name="lastName"><br>
<label for="email">Email</label><br>
<input type="text" v-model="email" name="email"><br>
<input class="addMemberBtn" type="submit" value="Submit">
</form>
<p v-if="errors.length">
<b>Please correct the following error(s):</b>
<ul>
<li v-for="error in errors">{{ error }}</li>
</ul>
</p>
</div>
<div class="teamContainer">
<h3 class="team_header">Team</h3>
<div class="team_content">
<div class="container">
<div class="searchbox">
<input class="search" type="text" placeholder="Search" v-model="search">
</div>
<div class="createMemberBtn">
<button>Add New Team Member</button>
</div>
</div>
<div class="view-members">
<table>
<tr>
<th>Name</th>
<th colspan="2">Status</th>
</tr>
<tr v-for="member in savedMembers">
<td>{{ member.firstName }} {{ member.lastName }}</td>
<td>{{ member.email }}</td>
</tr>
</table>
</div>
</div>
</div>
</div>
`,
data() {
return {
search: null,
firstName: null,
lastName: null,
email: null,
errors: [],
savedMembers: [],
};
},
methods: {
addNewTeamMember(newTeamMember) {
this.savedMembers.push(newTeamMember);
},
onSubmit() {
if (this.firstName && this.lastName && this.email) {
let newTeamMember = {
firstName: this.firstName,
lastName: this.lastName,
email: this.email,
};
this.addNewTeamMember(newTeamMember);
//this.$emit('members-submitted', newTeamMember)
this.firstName = null;
this.lastName = null;
this.email = null;
} else {
if (!this.firstName) this.errors.push("First name required");
if (!this.lastName) this.errors.push("Last name required");
if (!this.email) this.errors.push("Email required");
}
},
},
computed: {
/*filteredList() {
return this.savedMembers.filter((member) => {
return member.firstName
.toLowerCase()
.includes(this.search.toLowerCase());
});
},*/
},
});
var app = new Vue({
el: "#app",
data: {},
});
According to this part of the documentation:
"Computed properties are cached based on their reactive dependencies. A computed property will only re-evaluate when some of its reactive dependencies have changed."
Which means that, in your case, the filteredList would only change if the this.savedMembers array change.
So, the correct way would be that:
Create another array, let's assume filteredSavedMembers
You create a method to react whenever the search changes ( i.e <input #change="onSearchChange".../>
In this method, you will assign your filtering to the filteredSavedMembers
And that's it, now you only have to show your filterd list in the template.
*Obs: to filter by multiple values, you can use the or (||) operator, like this:
const search = this.search.toLowerCase()
this.filteredSavedMembers = this.savedMembers
.filter(({ firstName, lastName, email }) =>
firstName.toLowerCase().includes(search) ||
lastName.toLowerCase().includes(search) ||
email.toLowerCase().includes(search)
)

Vue add a component on button click

I have three templates. AddCard.vue , ImageCard.vue and VideoCard.vue
AddCard.vue has two buttons on it one is to add the Image Card and Other To Add the video Card.. I need to add components based on the button click. Here are three templates and my index.html file.
index.html
<!doctype html>
<html lang="en">
<head>
</head>
<body>
<div id="app">
<div class="container">
<div id="dynamic_components">
<!-- add components here -->
</div>
<addcard></addcard>
</div>
</div>
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
AddCard.vue
<template>
<div class="buttons">
ul class="no-margin-list">
<li #click="imagecard">
<span class="card_icon">
<img :src="'img/image.jpg'" >
</span>
<p>Add Image Card</p>
</a>
</li>
<li #click="videocard">
<span class="card_icon">
<img :src="'img/video.jpg'" >
</span>
<p>Add Video Card</p>
</a>
</li>
</div>
</template>
<script>
export default {
computed: {
},
methods: {
imagecard(val) {
//how to add image card
},
videocard() {
//how to add video card
}
},
}
</script>
ImageCard.vue
<template>
<h1> I am a image Card </h1>
</template>
<script>
</script>
VideoCard.vue
<template>
<h1> I am a Video Card </h1>
</template>
<script>
</script>
I need to add components dynamically one after another in the <div id="dynamic_components"> . User can add as many as cards they want.
How do I add the components dynamically. Please point me to a tutorial.
Uses v-for + dynamic component.
Vue.config.productionTip = false
Vue.component('card1', {
template: '<div>Card:<span style="background-color:green">{{title}}</span></div>',
props: ['title']
})
Vue.component('card2', {
template: '<div>Card:<span style="background-color:blue">{{title}}</span></div>',
props: ['title']
})
Vue.component('card3', {
template: '<div>Card:<span style="background-color:yellow">{{title}}</span></div>',
props: ['title']
})
new Vue({
el: '#app',
data() {
return {
cards: [
{'card': {'title': 'I am one card1'}, 'card-type':'card1'},
{'card': {'title': 'I am one card2'}, 'card-type':'card2'}
]
}
},
computed: {
computedNoCard1: function () {
let availableCards = new Set(['card2', 'card3'])
return this.cards.filter((item) => {
return availableCards.has(item['card-type'])
})
}
},
methods: {
addCard: function () {
let supportedCards = ['card1', 'card2', 'card3']
let seed = Math.floor(Math.random()*supportedCards.length)
this.cards.push({'card': {'title': 'I am new card for ' + supportedCards[seed]}, 'card-type': supportedCards[seed]})
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<button #click="addCard()">Add Card</button>
<table>
<tr><th>Data Property</th><th>Computed Property</th></tr>
<tr>
<td>
<div v-for="(card, index) in cards" :key="index">
<component :is="card['card-type']" :title="card.card.title">
</component>
</div>
</td>
<td>
<div v-for="(card, index) in computedNoCard1" :key="index">
<component :is="card['card-type']" :title="card.card.title">
</component>
</div>
</td>
</tr>
</table>
</div>

Validation Error messages on form load

About the issue
I am using Laravel 5.6.7 with vue.js. vee-validate is being used for validation
When the form loads, it shows validation error messages. User did not even click the submit button. Below is the screenshot.
Code
<template>
<div>
<form role="form">
<input v-validate data-vv-rules="required" type="text"
v-model="UpdateForm.First_Name">
<p v-if="errors.has('First Name')">{{ errors.first('First Name') }}</p>
<button type="button">
Update Profile
</button>
</form>
</div>
</template>
<script>
export default {
data() {
return {
UpdateForm: {
First_Name: ''
}
}
},
created() {
this.GetProfile();
},
methods: {
GetProfile() {
axios.post("some api url", {}).then(response => {
this.UpdateForm.First_Name = response.data.Data.First_Name;
});
}
}
}
</script>
Could I get rid of validation error messages on form load?
This is not the expected behavior. For initial validating you need to inform it with v-validate.initial.
Maybe you are defining this to happen when declaring v-validate or in other place.
Vue.use(VeeValidate);
new Vue({
el: '#demo'
})
.is-danger{
color: red;
}
<script src="https://unpkg.com/vue"></script>
<script src="https://cdn.jsdelivr.net/npm/vee-validate#latest/dist/vee-validate.js"></script>
<div id="demo">
<label>This one needs touching</label>
<input type="text" name="name" v-validate="'required'">
<div v-show="errors.has('name')" class="is-danger">Errors: {{ errors.first('name') }}</div>
<br/>
<label>This one does not need touching</label>
<input name="name2" v-validate.initial="'required'" type="text">
<div v-show="errors.has('name2')" class="is-danger">{{ errors.first('name2') }}</div>
</div>
Changed
this.editForm.First_Name = Data.User.First_Name;
to
if(Data.User.First_Name != null && Data.User.First_Name != "") {
this.editForm.First_Name = Data.User.First_Name;
}
and validation is working fine now. Basically the variable is not initialized.

Vue js event not picked up

I have just started experimenting with vue js and I am building a checkout form with it. I am also using Symfony 31 for the project. On the checkout/signup page I have an embedded collection of forms representing order items (each are subscription to a type of product). You can select multiple items by ticking a checkbox. You can also change the quantity. Unfortunately I cannot manage to pass the quantity update to the Vue instance. The entries are registered on render with the quantity 1, and if I change the quantity and then select the item, the price is calculated correctly, but the app registers this as a new entity. The binding with the quantity is not working. I will also need to add a similar field called frequency and I know I will have the same problem. Help?
Here is the js fiddle: https://jsfiddle.net/wavsu8xm/
Javascript:
var bus = new Vue();
var entriesComponent = Vue.component('entries', {
template: '#entries',
props: {
entries: [Array, Object],
selected: Array,
addons: Array,
frequencies: [Array, Object],
},
watch: {
selected: function(val, oldVal) {
bus.$emit('selected-changed', val);
},
}
});
new Vue({
el: '#app',
data: {
entries: [],
selected: [],
addons: [],
frequencies: [],
paymentConfig: {
advance: 25,
firstweek: 25,
ondelivery: 50,
},
weeks: 12,
},
components: {
'entriesComponent': entriesComponent,
},
created: function() {
// store this to use with Vue.set
var temp = this;
bus.$on('selected-changed', function(selected) {
// vm.$set deprecated
Vue.set(temp, 'selected', selected);
});
},
computed: {
totalAdvance: function() {
return (this.paymentConfig.advance * this.total) / 100;
},
totalFirstWeek: {
get: function() {
return (this.paymentConfig.firstweek * this.total) / 100;
},
},
onDeliveryPayment: {
get: function() {
return (this.paymentConfig.ondelivery * this.total) / (this.weeks * 100);
}
},
total: {
get: function() {
var sum = 0;
var weeks = this.weeks;
this.selected.forEach(function(item) {
sum += weeks * item.itemPrice * item.quantity;
});
console.log(sum);
return sum;
}
}
}
});
Template:
<section class="content">
<div class="row" id="app">
<div class="col-md-8">
<div class="box box-primary">
<div class="box-body">
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label class="control-label required">Items</label>
<div class="col-md-12">
<entries :entries="{ 0 : { shareSize : 'Small', quantity : '1', itemPrice : '24', frequency : '' }, 1 : { shareSize : 'Medium', quantity : '1', itemPrice : '35', frequency : '' }, 2 : { shareSize : 'Large', quantity : '1', itemPrice : '46', frequency : '' } }"
:selected="selected"></entries>
<!-- component template -->
<template id="entries">
<div class="col-md-12">
<div class="form-group" v-for="(entry, key) in entries" v-bind:entry="entry">
<div class="form-group col-md-12">
<div class="col-md-12">
<div class="col-md-4">
<input type="checkbox" v-bind:value="entry" v-model="selected">
</div>
<div class="col-md-4">{{entry.shareSize}}</div>
<div class="col-md-4">{{'$ ' + Number(entry.itemPrice).toFixed(2) }}</div>
</div>
<div class="form-group col-md-12">
<div class="col-md-6">
<input type="number" v-model="entry.quantity" :value="entry.quantity" />
</div>
</div>
</div>
</div>
</div>
</template>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="box box-info">
<div class="box-body" style="padding:15px;">
<div class="container-fluid">
<div class="form-group">
<div class="control-label">
<label>Summary</label>
</div>
<div class="form-control" v-for="item in selected">
<span class="pull-left small-box-footer">{{ item.shareSize }}</span>
<span class="pull-right">{{ item.quantity + ' x $ ' + (item.itemPrice*item.quantity).toFixed(2)}}</span>
</div>
<div class="control-label">
<label>Payment plan</label>
</div>
<div class="col-md-12">
{{ '$ ' + totalAdvance.toFixed(2) }} - advance
</div>
<div class="col-md-12">
{{ '$ ' + totalFirstWeek.toFixed(2) }} - first week
</div>
<div class="col-md-12">
{{ '$ ' + onDeliveryPayment.toFixed(2) }}/ week on each of the {{ weeks }} weeks of the subscription
</div>
<div class="col-md-12 row">
<div class="control-label"><strong><span class="pull-left">Total</span><span class="pull-right">{{ '$ ' + total.toFixed(2) }}</span></strong></div>
</div>
<div class="col-md-12 row">
<div class="title"><strong><span class="pull-left">Total due now</span><span class="pull-right">{{ '$ ' + totalAdvance.toFixed(2) }}</span></strong></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
You are mutating your props directly which will get overwritten when the parent component re-renders, so you need to make a copy of them inside your component, which can be done inside the created method of your component:
created: function() {
// copy props to data
this.entriesCopy = this.entries;
this.selectedCopy = this.selected;
},
data: function() {
return{
entriesCopy: [],
selectedCopy: []
}
}
Now you just need to update your watcher:
watch: {
selectedCopy: function(val, oldVal) {
bus.$emit('selected-changed', val);
}
}
And your template:
//...
div class="form-group" v-for="(entry, key) in entriesCopy" v-bind:entry="entry">
//...
<input type="checkbox" v-bind:value="entry" v-model="selectedCopy">
to reflect the changes.
Here's the updated jsfiddle: https://jsfiddle.net/5pyw74h9/