Vue.js remove element from list - javascript

I am trying to create a simple webpage where I can add or remove textboxes using vue.js.
new Vue({
el: "#app",
data() {
return {
list: []
};
},
methods: {
deleteFromList(index) {
this.list.splice(index, 1);
},
addItem() {
this.list.push({});
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<button #click="addItem()">Add 1</button>
<ul>
<li v-for="(item, index) in list":key="index">
<textarea rows="1" cols="30">{{item}}</textarea>
<button #click="deleteFromList(index)">Delete</button>
</li>
</ul>
</div>
<script src="index.js"></script>
</body>
</html>
I added a snippet to the page (I think you need to expand or make it full screen to see the result properly), my problem is that on Delete button it doesn't remove the corresponding row, but the last one.
Has anyone any idea about how can I do this work fine?
Thank you very much :)

It is actually removing the correct item out of the array, but you're not seeing it because you're not changing the value of the model only the textarea which is not tied to the value instead its just cached to :key="index", below is an example which should show that, simply by adding a counter you can see it's deleting the correct object.
Vue.config.productionTip = false;
Vue.config.devtools = false;
new Vue({
el: "#app",
data() {
return {
list: [],
counter: 0,
};
},
methods: {
deleteFromList(index) {
this.list.splice(index, 1);
},
addItem() {
this.list.push(this.counter++);
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<button #click="addItem()">Add 1</button>
<ul>
<li v-for="(item, index) in list" :key="index">
<textarea rows="1" cols="30">{{item}}</textarea>
<button #click="deleteFromList(index)">Delete</button>
</li>
</ul>
<pre>{{ list }}</pre>
</div>
To fix the issue and have dynamic changing values/model you should use v-model on the value and indexOf when removing.
Vue.config.productionTip = false;
Vue.config.devtools = false;
new Vue({
el: "#app",
data() {
return {
list: []
};
},
methods: {
deleteFromList(item) {
this.list.splice(this.list.indexOf(item), 1);
},
addItem() {
this.list.push('');
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<button #click="addItem()">Add 1</button>
<ul>
<li v-for="(item, index) in list" :key="index">
<textarea rows="1" cols="30" v-model="list[index]"></textarea>
<button #click="deleteFromList(item)">Delete</button>
</li>
</ul>
</div>

Related

How do I make it so that I can edit my vue to do list to add items?

Ok, so, I am new to Vue and I am trying to make a simple to do list. I have managed to display it and stuff but I am having trouble with the code to add items to the list. When I click the button to add the task, it adds a bullet point but it doesn’t show the text given. For example, in the input box, I will type the name of a task but when I click the button, what I wrote doesn’t show up, just the bullet point.
I have tried putting the newTask part in other places but the same problem happens. I know this is probably a pretty silly question and the solution is probably pretty obvious but please help as fast as you can, I need to do this for school.
Here is my HTML:
<body>
<div id="app">
<!-- Vue App HTML Code -->
<h1>To Do List</h1>
<div id="app">
<ul>
<li v-for="x in tasks">
{{ x.text }}
</li>
</ul>
</div>
<div id="newTask">
<input type="text" value="taskName" placeholder="Task Name" v-model="newTask"></input>
<button v-on:click="tasks.push(newTask)">Add Task</button>
</div>
</body>
And my JavaScript/ Vue:
myObject = new Vue({
el: '#app',
data: {
tasks: [
{ text: '1' },
{ text: '2' },
{ text: '3' },
],
newTask: ''
},
})
I would really appreciate any other Vue tips (relevant or not) because it is my first week learning it and anything would be really useful.
You can achieve this by pushing the newTask in the existing tasks array.
Working Demo :
var vm = new Vue({
el: '#app',
data: {
tasks: [
{ text: '1' },
{ text: '2' },
{ text: '3' },
],
newTask: ''
},
methods: {
addTask() {
this.tasks.push({ text: this.newTask })
this.newTask = '';
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h1>To Do List</h1>
<ul>
<li v-for="x in tasks">
{{ x.text }}
</li>
</ul>
<input type="text" placeholder="Task Name" v-model="newTask"/>
<button v-on:click="addTask">Add Task</button>
</div>

appending vuejs data to a div

I have something I have been trying to do which is challenging. I have a simple div that gets appended to the top level on the click of a button. The issue is I want vuejs data appended inside of this div. I am not quite sure how to bind this data, I have tried using a simple expression, but no luck. Can someone please let me know how this can be solved--and with a div, not a bootstrap modal
new Vue({
el: "#app",
data: {
chocs:[{"title":'a man tale'},{"title":'a boy tale'}]
},
methods: {
handleTileClick: function(){
alert(this.chocs[0].title);
$("#fox").append(`<div id="popover-dialog"> data here {{this.chocs[0].title}}
</div>`);
},
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<div id="app">
<h2>Todos:</h2>
<button v-on:click="handleTileClick()">
Click Me
</button>
<div id="fox">
</div>
</div>
Without JQuery, the Vue-way:
new Vue({
el: "#app",
data: () => ({
chocs:[{"title":'a man tale'}, {"title":'a boy tale'}],
titleToBeAppended: ''
}),
methods: {
handleTileClick: function(){
this.titleToBeAppended = this.chocs[0].title
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div id="popover-dialog">
<p>Data here: {{ titleToBeAppended }}</p>
<button v-on:click="handleTileClick()">Click Me</button>
</div>
</div>
Using template literals:
new Vue({
el: "#app",
data: () => ({
chocs:[{"title":'a man tale'}, {"title":'a boy tale'}]
}),
methods: {
handleTileClick: function(){
alert(this.chocs[0].title);
$("#fox").append(
`<div id="popover-dialog">data here: ${this.chocs[0].title}</div>`
);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<div id="app">
<h2>Todos:</h2>
<button v-on:click="handleTileClick()">Click Me</button>
<div id="fox"></div>
</div>

v-for is rendering my list in one row with many columns instead of one column with many rows

I want my list to be rendered like this:
A
B
C
Right now its being rendered like this:
1: A 2: B 3: C
Heres the code:
Todos:
<input type="text" class = "todo" placeholder = "Next Item" v-on:keyup.enter="addItem()">
<ol>
<li v-for="(todo, index) in todos" class ="todos">
{{index}}: {{ todo.text }}
</li>
</ol>
Heres the javascript portion:
addItem(){
var text = event.target.value;
this.todos.push({text, done: false, id: Date.now()})
text = '';
}
Any help would be very appreciated!
Not entirely sure why yours is displaying any different, but here's a rough example:
new Vue({
el: '#app',
data() {
return {
todos: ['derek', 'was', 'here'],
newTodo: ''
}
},
methods: {
addTodo() {
this.todos.push(this.newTodo);
this.newTodo = '';
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div>
<input v-model="newTodo" />
<button #click="addTodo">add</button>
<ol>
<li v-for="(todo, index) in todos" :key="index">{{todo}}</li>
</ol>
</div>
</div>
The only other thing I can think of is that you have some special CSS styling set that's causing the issue.

Vue Component, toggle data

Think i'm cracking up, this is some very basic stuff but it doesn't seem to be working...
Basically clicking the link should toggle display between true and false, but this isn't the case.
Vue.component('dropdown', {
props: [ 'expanded' ],
data: function() {
return {
display: !!(this.expanded)
}
},
template: '<div><transition name="expand"><slot :display="display"></slot></transition></div>'
});
window.app = new Vue({
el: '#app'
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<dropdown>
<div slot-scope="{ display }">
Toggle {{ display }}
<div v-if="display">
Dropdown content
</div>
</div>
</dropdown>
</div>
Edit:
Updated code, I forgot I changed that, I did infact have the click event as display = !display. But even with that said, if you had tried to click the button you would see that it doesn't change the true either...
Updating after a correcting comment from thanksd. I stumbled onto the right answer without really understanding it.
The problem is that within the slot, display refers to an item in the scope-slot object. Updating it there does not update the actual source variable. If you pass in and call a function, the proper variable is updated.
Vue.component('dropdown', {
props: ['expanded'],
data: function() {
return {
display: Boolean(this.expanded)
}
},
methods: {
toggle() {
this.display = !this.display;
}
},
template: '<div><transition name="expand"><slot :display="display" :toggle="toggle"></slot></transition></div>'
});
new Vue({
el: '#app'
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<dropdown>
<div slot-scope="{display, toggle}">
Toggle {{ display }}
<div v-if="display">
Dropdown content
</div>
</div>
</dropdown>
</div>
One solution would be to implement a v-model for the dropdown component which would allow you to two-way bind the display property to a property in the parent. That way you wouldn't need to pass anything via the slot-scope.
Here's an example of that:
Vue.component('dropdown', {
props: [ 'value' ],
data() {
return {
display: !!(this.value)
}
},
watch: {
value(value) {
this.$emit('input', value);
}
},
template: '<div><transition name="expand"><slot></slot></transition></div>'
});
new Vue({
el: '#app',
data() {
return { dropdownToggle: false }
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<dropdown v-model="dropdownToggle">
<div>
<a href="javascript:void(0)" #click="dropdownToggle = !dropdownToggle">
Toggle {{ dropdownToggle }}
</a>
<div v-if="dropdownToggle">
Dropdown content
</div>
</div>
</dropdown>
</div>

Vue v-model not updating array values while using v-for

I'm new to Vue, and am playing around with v-model to see what I can create. I want to make an editable array of names. Here is my code so far:
var app = new Vue({
el: '#app',
data: {
names: ['Josh', 'Tom']
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>
<div id="app">
Editable list:
<ul>
<li v-for="name in names"><input type="text" v-model="name"></li>
</ul>
{{ names }}
</div>
When this is run, the inputs show up, and each one contains the correct value. However, typing in the inputs doesn't update the names array as I would have expected.
What am I doing wrong?
You're trying to use v-model to operate on a value, whereas you need to operate on a vue data field. For example, try the following:
var app = new Vue({
el: '#app',
data: {
people: [{name: 'Josh'}, {name: 'Tom'}]
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>
<div id="app">
Editable list:
<ul>
<li v-for="person in people"><input type="text" v-model="person.name"></li>
</ul>
{{ people }}
</div>
Alternatively, you could do:
var app = new Vue({
el: '#app',
data: {
names: ['Josh', 'Tom']
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>
<div id="app">
Editable list:
<ul>
<li v-for="(name, index) in names"><input type="text" v-model="names[index]"></li>
</ul>
{{ names }}
</div>

Categories