How to add items in list on button click? - javascript

Could you please tell me how to add an item to list on button click. Here is my code
https://plnkr.co/edit/hVQKk3Wl9DF3aNx0hs88?p=preview
var AddTODO = Vue.extend({
template: '#add-todo',
props: ['m'],
data: function () {
return {
message: ''
}
},
methods: {
addTodo: function () {
console.log(this.message)
console.log(this.m);
//this.m =this.message;
},
},
});
<template id="add-todo">
<div>
<input type="text" v-model="m">
<button #click="addTodo">Add todo</button>
</div>
</template>
is there any way to add items

Related

Vue js: How to hide button

i'm new to Vue js in this code below , i wanted to hide button "Clear Filter" when nothing selected and show the button only when function " selectedAnswer(index)" called so that it will show only when filter applied otherwise it should be hided , is there a way to do it in my code?
and thanks in advance
<template>
<div class="container" width=800px>
<b-row>
<b-col cols="8">
<h1> Recently Asked </h1>
<ul class="container-question" v-for="(question1,index) in questions" :key="index">
<li>
{{question1.question}}
</li>
</ul>
</b-col>
<b-button class="outline-primaryy" style="margin:auto;" #click="ClearFilter" >Clear Filter</b-button>
</div>
<router-view />
</div>
</template>
<script>
export default {
data() {
return {
questions: [],
answered: null,
index: 0,
selectedIndex: null,
}
},
methods: {
selectedAnswer(index) {
this.selectedIndex = index;
this.questions = this.questions.filter((question) => question.incorrect_answers.includes(index))
console.log(index)
},
ClearFilter() {
this.questions = this.unmutated
},
watch: {
question1: {
handler() {
this.selectedIndex = null;
this.answered = false;
},
},
},
},
mounted: function() {
fetch('https://opentdb.com/api.php?amount=10&category=9&difficulty=medium&type=multiple', {
method: 'get'
})
.then((response) => {
return response.json()
})
.then((jsonData) => {
this.questions = jsonData.results
this.unmutated = jsonData.results;
})
}
}
</script>
You just need to add a v-if="selectedIndex" to your btn element.
ie
<b-button v-if="selectedIndex" class="outline-primaryy" style="margin:auto;" #click="ClearFilter" >Clear Filter</b-button

How can I filter object with VueJS?

I've been practicing Vue.js recently.
Right now, I am making a simple todo list.
Some buttons does't work which filter tasks.
All button for listing every single tasks.
ongoing button is for uncheck input checkbox square.
done button is for checked ones.
Does anybody know how to fix?
new Vue({
el: '#app',
data: {
inputTask:'',
todos: [
{task:'task01', done: false},
{task:'task02', done: false},
{task:'task03', done: true},
{task:'task04', done: true},
{task:'task05', done: false},
]
},
computed: {
},
methods: {
allTask : function () {
this.todos
},
ongoingTask: function () {
this.todos = this.todos.filter(function (el) {
el.value = false
})
},
doneTask: function () {
this.todos = this.todos.filter(function (el) {
el.checked
})
},
addTask: function() {
const todo = { task: this.inputTask, done:false, };
this.todos.push(todo);
this.inputTask ='';
},
deleteTask: function (index) {
this.todos.splice(index, 1);
}
}
})
.done {text-decoration: line-through;}
<div id="app">
<input type="text" v-model="inputTask">
<button #click="addTask">Add</button>
<div>
<button #click="allTask">All</button>
<button #click="ongoingTask">Ongoing</button>
<button #click="doneTask">Done</button>
</div>
<ul>
<li v-for="(todo, index) in todos" :key="todo">
<input type="checkbox" v-model="todo.done">
<span :class="{done:todo.done}">{{todo.task}}</span>
<button #click="deleteTask(index)">Remove</button>
</li>
</ul>
<p v-show="todos.length===0">Nothing to do</p>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
You should use computed property to filter your task. And i guess you can add some improvements for user friendly interface. So your code will look like this:
new Vue({
el: '#app',
data: {
type: '',
inputTask:'',
todos: [
{task:'task01', done: false},
{task:'task02', done: false},
{task:'task03', done: true},
{task:'task04', done: true},
{task:'task05', done: false},
]
},
methods: {
setFilterType(type) {
this.type = type;
},
addTask() {
const todo = { task: this.inputTask, done: false};
this.todos.push(todo);
this.inputTask = '';
},
deleteTask(index) {
this.todos.splice(index, 1);
}
},
computed: {
filteredTodos() {
return this.todos.filter(todo => {
switch(this.type) {
case 'ongoing':
return !todo.done;
case 'done':
return todo.done;
default:
return true;
}
});
}
}
})
And template:
<div id="app">
<input type="text" v-model="inputTask">
<button #click="addTask">Add</button>
<div>
<button :class="{active: type ===''}" #click="setFilterType('')">All</button>
<button :class="{active: type ==='ongoing'}" #click="setFilterType('ongoing')">Ongoing</button>
<button :class="{active: type ==='done'}" #click="setFilterType('done')">Done</button>
</div>
<ul>
<li v-for="(todo, index) in filteredTodos" :key="todo">
<input type="checkbox" v-model="todo.done">
<span :class="{done:todo.done}">{{todo.task}}</span>
<button #click="deleteTask(index)">Remove</button>
</li>
</ul>
<p v-show="todos.length===0">Nothing to do</p>
</div>
Also i've added active class to button. So you can highlight via css current sorting.
More about computed you can read here
All your filter function on ongoingTask and doneTask are wrong, they should return a value; take a look at how filter function works: here.
I'm not sure what's the intended behavior of ongoingTaks is, but I guess the following should solve the problem. Please let me know and I'll update the answer correspondingly.
// ...
ongoingTask: function () {
this.todos = this.todos.filter(function (el) {
return el.value === false
})
},
doneTask: function () {
this.todos = this.todos.filter(function (el) {
return el.checked
})
},
// ...
EDIT:
The other part of the issue had to do with the logic, as soon as you clicked on any button that triggers the filtering, data in the state is removed (for instance, if I'm in the default view, viewing all todos, when I click in the Ongoing button, all the done TODO in the list gets removed and forever lost!); ideally you should keep that data and use computed properties to tackle the issue, here you have a working example (I'm using a Vue component here just for the sake of condensing all data in one place):
<template>
<div id="app">
<input type="text" v-model="inputTask">
<button #click="addTask">Add</button>
<div>
<button #click="changeFilter('all')">All</button>
<button #click="changeFilter('ongoing')">Ongoing</button>
<button #click="changeFilter('done')">Done</button>
</div>
<ul>
<li v-for="(todo, index) in getTasksList()" :key="{index}">
<input type="checkbox" v-model="todo.done">
<span :class="{done:todo.done}">{{todo.task}}</span>
<button #click="deleteTask(index)">Remove</button>
</li>
</ul>
<p v-show="todos.length===0">Nothing to do</p>
</div>
</template>
<script>
export default {
name: "App",
data: () => ({
inputTask: "",
currentFilter: "ongoing",
todos: [
{ task: "task01", done: false },
{ task: "task02", done: false },
{ task: "task03", done: true },
{ task: "task04", done: true },
{ task: "task05", done: false }
]
}),
computed: {
ongoingTasks: function() {
return this.todos.filter(function(todo) {
return todo.done === false;
});
},
doneTasks: function() {
return this.todos.filter(function(el) {
return el.done;
});
}
},
methods: {
changeFilter(newFilter) {
this.currentFilter = newFilter;
},
addTask: function() {
const todo = { task: this.inputTask, done: false };
this.todos.push(todo);
this.inputTask = "";
},
deleteTask: function(index) {
this.todos.splice(index, 1);
},
getTasksList() {
switch (this.currentFilter) {
case "ongoing":
return this.ongoingTasks;
case "done":
return this.doneTasks;
case "all":
default:
return this.todos;
}
}
}
};
</script>
I hope this helps!

Retain filled form fields on page refresh in Vue

The issue I am facing here is, I am not able to figure out how can I retain the values in the form on page refresh. Each time I refresh the page all the filled values in the form are gone.
Help me resolve this issue. I was thinking of using localStorage but not sure how I can implement it.
<template>
<v-card class="mb-12">
<v-form :model='user' class="content-padding" ref='pdfInputs'>
<div class="section-header">
User
</div>
<v-container fluid>
<ul>
<li v-for="(input, index) in user.inputs">
<input type="text" v-model="input.one"> - {{ input.one }}
<input type="text" v-model="input.two"> - {{ input.two }}
<button type="button" #click="deleteRow(index)">Delete</button>
</li>
</ul>
</v-container>
</v-form>
</v-card>
</template>
<script>
export default {
data () {
return {
user: {
inputs: []
}
}
}
methods: {
addRow() {
this.user.inputs.push({
one: '',
two: ''
})
},
deleteRow(index) {
this.user.inputs.splice(index,1)
}
}
}
</script>
There is watch functionality in vue
export default {
data () {
return {
user: {
inputs: []
}
}
},
mounted() {
this.user.inputs = JSON.parse(localStorage.getItem('form')) || [];
},
watch: {
user: {
handler: function() {
localStorage.setItem('form', JSON.stringify(this.user.inputs));
},
deep: true
}
},
methods: {
addRow() {
this.user.inputs.push({
one: '',
two: ''
})
},
deleteRow(index) {
this.user.inputs.splice(index,1)
}
}
}

Remove dynamically created Vue Components

I followed the solution to create dynamic form elements here:
Dynamically adding different components in Vue
Works great, my next conundrum is now I want to remove form elements if the user adds too many.
The way it works is the user creates a "set" which is defined as a group of inputs. So each set could be for a different person, or place, etc.
Here is my JSfiddle https://jsfiddle.net/61x784uv/
Html
<div id="component-pii-input" v-for="field in fields" v-bind:is="field.type" :key="field.id">
</div>
<button id='button-add-pii-component' v-on:click="addFormElement('pii-entry-field')">Add Set</button>
</div>
Javascript
Vue.component('pii-entry-field', {
data: function () {
return {
fields: [],
count: 0,
}
},
methods: {
addFormElement: function(type) {
this.fields.push({
'type': type,
id: this.count++
});
},
},
template: ` <div class='pii-field'><div>
<component v-for="field in fields" v-bind:is="field.type":key="field.id"></component>
</div>
<button id='button-add-pii-input' v-on:click="addFormElement('pii-input-field')">Add Input</button>
<hr>
</div>`,
})
Vue.component('pii-input-field', {
data: function () {
return {
}
},
template: ` <div>
<select>
<option disabled>Select Classification</option>
<option>Name</option>
<option>Address</option>
<option>Email</option>
<option>Phone</option>
<option>Medical</option>
<option>Financial</option>
</select>
<div>
<input type="text" placeholder="Input">
</div>
<button v-on:click="removeFormElement">Remove Input</button></span>
</div>`,
})
var app = new Vue({
el: '#app',
data: {
fields: [],
count: 0,
},
methods: {
addFormElement: function(type) {
this.fields.push({
'type': type,
id: this.count++
});
},
}
});
Here is a working fiddle: https://jsfiddle.net/e12hbLcr/
Walkthrough:
You need to give the component some kind of id to know what component should be removed. You can do this with props.
<component v-for="field in fields" v-bind:is="field.type" :id="field.id" :key="field.id">
Now create the function in the child-component and edit the button so it sends the id.
<button v-on:click="removeFormElement(id)">Remove Input&lt/button>
Remember in Vue that props go down (parent -> child) and events up (child-parent). So now we need to tell the parent that this button was clicked and an id was sent.
removeFormElement(id) {
console.log('sending message up to remove id', id)
this.$emit('remove', id)
}
Tell the parent component to listen to that event and attach a function to that event.
<component v-for="field in fields" v-bind:is="field.type" :id="field.id" #remove="removeFormElement" :key="field.id">
Note that the # is same as v-on:
Finally remove that item from the fields array.
removeFormElement(id) {
console.log('removing form element', id)
const index = this.fields.findIndex(f => f.id === id)
this.fields.splice(index,1)
}
You should probably move these remove buttons into a <slot> of the component so you could pass in the scoped id.
But if you can't, you could $emit removal event on the $parent of the individual components, passing the id of the item to remove.
Vue.component('pii-entry-field', {
data() {
return {
fields: [],
count: 0,
}
},
mounted() {
this.$on('removeFormElement', this.removeFormElement);
},
methods: {
addFormElement(type) {
this.fields.push({
'type': type,
id: this.count++
});
},
removeFormElement(id) {
const index = this.fields.findIndex(f => f.id === id);
this.fields.splice(index, 1);
}
},
template: `
<div class='pii-field'>
<component v-for="field in fields" v-bind:is="field.type" :key="field.id"></component>
<button id='button-add-pii-input' v-on:click="addFormElement('pii-input-field')">Add Input</button>
<hr>
</div>`,
})
Vue.component('pii-input-field', {
data() {
return {
}
},
methods: {
removeFormElement() {
const id = this.$vnode.key;
this.$parent.$emit('removeFormElement', id);
}
},
template: `
<div>
<select>
<option disabled>Select Classification</option>
<option>Name</option>
<option>Address</option>
<option>Email</option>
<option>Phone</option>
<option>Medical</option>
<option>Financial</option>
</select>
<div>
<input type="text" placeholder="Input" />
</div>
<button v-on:click="removeFormElement">Remove Input</button>
</div>`,
})
var app = new Vue({
el: '#app',
data() {
return {
fields: [],
count: 0,
}
},
methods: {
addFormElement(type) {
this.fields.push({
'type': type,
id: this.count++
});
},
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div id="component-pii-input" v-for="field in fields" v-bind:is="field.type" :key="field.id">
</div>
<button id="button-add-pii-component" v-on:click="addFormElement('pii-entry-field')" class="uk-button uk-button-primary uk-width-1-1 uk-margin-small">Add Set</button>
</div>

Click-and-edit text input with Vue

I'm looking for a click-and-edit Vue component.
I've found a fiddle and made some edits. It works like this:
The fiddle is here.
The problem: I need an additional click to make the input focused. How can I make it focused automatically?
The code from the fiddle. HTML:
<div id="app">
Click the values to edit!
<ul class="todo-list">
<li v-for = "todo in todos">
<input v-if = "todo.edit" v-model = "todo.title"
#blur= "todo.edit = false; $emit('update')"
#keyup.enter = "todo.edit=false; $emit('update')">
<div v-else>
<label #click = "todo.edit = true;"> {{todo.title}} </label>
</div>
</li>
</ul>
</div>
JS:
new Vue({
el: '#app',
data: {
todos: [{'title':'one value','edit':false},
{'title':'one value','edit':false},
{'title':'otro titulo','edit':false}],
editedTodo: null,
message: 'Hello Vue.js!'
},
methods: {
editTodo: function(todo) {
this.editedTodo = todo;
},
}
})
You can use a directive, for example
JS
new Vue({
el: '#app',
data: {
todos: [
{ title: 'one value', edit: false },
{ title: 'one value', edit: false },
{ title: 'otro titulo', edit: false }
],
editedTodo: null,
message: 'Hello Vue.js!'
},
methods: {
editTodo: function (todo) {
this.editedTodo = todo
}
},
directives: {
focus: {
inserted (el) {
el.focus()
}
}
}
})
HTML
<div id="app">
Click the values to edit!
<ul class="todo-list">
<li v-for="todo in todos">
<input
v-if="todo.edit"
v-model="todo.title"
#blur="todo.edit = false; $emit('update')"
#keyup.enter="todo.edit=false; $emit('update')"
v-focus
>
<div v-else>
<label #click="todo.edit = true;"> {{todo.title}} </label>
</div>
</li>
</ul>
</div>
You can find more info here
https://v2.vuejs.org/v2/guide/custom-directive.html
With #AitorDB's help I have written a Vue component for this, I call it Click-to-Edit. It is ready to use, so I'm posting it.
What it does:
Supports v-model
Saves changes on clicking elsewhere and on pressing Enter
ClickToEdit.vue: (vue 2.x)
<template>
<div>
<input type="text"
v-if="edit"
:value="valueLocal"
#blur.native="valueLocal = $event.target.value; edit = false; $emit('input', valueLocal);"
#keyup.enter.native="valueLocal = $event.target.value; edit = false; $emit('input', valueLocal);"
v-focus=""
/>
<p v-else="" #click="edit = true;">
{{valueLocal}}
</p>
</div>
</template>
<script>
export default {
props: ['value'],
data () {
return {
edit: false,
valueLocal: this.value
}
},
watch: {
value: function() {
this.valueLocal = this.value;
}
},
directives: {
focus: {
inserted (el) {
el.focus()
}
}
}
}
</script>
Edit for 3.x: [Breaking changes between 2.x and 3.x]
remove .native from the event handlers
change the focus hook to mounted as described in Custom Directives 3.x.
Built on #Masen Furer's work. I added some protection to handle when a user deletes all of the data. There is probably a way to accomplish this using "update" but I couldn't get it working.
I also added the ability to hit escape and abandon any changes.
<template>
<span>
<input type="text"
v-if="edit"
:value="valueLocal"
#blur="save($event);"
#keyup.enter="save($event);"
#keyup.esc="esc($event);"
v-focus=""/>
<span v-else #click="edit = true;">
{{valueLocal}}
</span>
</span>
</template>
<script>
export default {
props: ['value'],
data () {
return {
edit: false,
valueLocal: this.value,
oldValue: (' ' + this.value).slice(1)
}
},
methods: {
save(event){
if(event.target.value){
this.valueLocal = event.target.value;
this.edit = false;
this.$emit('input', this.valueLocal);
}
},
esc(event){
this.valueLocal = this.oldValue;
event.target.value = this.oldValue;
this.edit = false;
this.$emit('input', this.valueLocal);
}
},
watch: {
value: function() {
this.valueLocal = this.value;
}
},
directives: {
focus: {
inserted (el) {
el.focus()
}
}
}
}
</script>

Categories