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>
Related
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>
Background: I have a list of checkboxes that is bound to a names array. I am trying to change the class of the specific name once the checkbox is clicked.
Problem: Once a checkbox is clicked it changes the class of all the names instead of the specific name attached to the checkbox.
JSFiddle of the issue:
JSFiddle
HTML
<div id="app">
<ul>
<li v-for="name in names" :key="index">
<input #click="available = !available" type="checkbox">
<label :class="{available:available}" >{{name.name}}</label>
</li>
</ul>
</div>
Vue instance
var app = new Vue({
el: '#app',
data: {
available: false,
names: [{'name':'Jerry'},{'name':'Eddie'},{'name':'Kerry'},{'name':'Jane'}]
}
})
Css
.available{
text-decoration: line-through;
}
Ad the available variable to each name object and use a method to update the available property:
var app = new Vue({
el: '#app',
data: {
names: [
{'name':'Jerry', 'available': false},
{'name':'Eddie', 'available': false},
{'name':'Kerry', 'available': false},
{'name':'Jane', 'available': false}
]
},
methods: {
updateAvailable(index) {
// Update the available property on the specific object with its index
this.names[index].available = !this.names[index].available
}
}
})
Then in your template, call the method updateAvailable:
<div id="app">
<ul>
<li v-for="(name, index) in names" :key="index">
<input #click="updateAvailable(index)" type="checkbox">
<label :class="{available: name.available}" >{{name.name}}</label>
</li>
</ul>
</div>
Move the available property in to each name element and toggle name.available in your template. You can even use v-model on your checkboxes.
const names = [{'name':'Jerry'},{'name':'Eddie'},{'name':'Kerry'},{'name':'Jane'}]
const app = new Vue({
el: '#app',
data: () => ({
names: names.map(name => ({ ...name, available: false }))
})
})
.available {
text-decoration: line-through;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<div id="app">
<ul>
<li v-for="(name, i) in names">
<input :id="`name_${i}`" v-model="name.available" type="checkbox">
<label :for="`name_${i}`" :class="{ available: name.available }">
{{name.name}}
</label>
</li>
</ul>
</div>
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.
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>
So I just started playing around with Vue.js. But I am having some problems with simple tasks like adding new "news item" to the array. JSFiddle included so if someone can tell me what I am doing wrong..
http://jsfiddle.net/pL5taqp6/
HTML
<div id="app">
<input type="text" v-model="news.title">
<input type="text" v-model="news.url">
<ul>
<li v-for="n in news">
{{ n.title }} - {{ n.url }}
</li>
</ul>
</div>
JS
new Vue({
el: '#app',
data: {
news: [
{ title: 'Test Title', url: '/test-title'}
]
}
});
You need a separate method to add items to news array. I added super simple variant of such function.
http://jsfiddle.net/00953sor/
HTML:
<div id="app">
<form #submit="addItem">
<input type="text" v-model="itemTitle">
<input type="text" v-model="itemUrl">
<button type="submit">Add</button>
</form>
<ul>
<li v-for="n in news">
{{ n.title }} - {{ n.url }}
</li>
</ul>
<pre>{{ $data | json }}</pre>
</div>
JavaScript:
new Vue({
el: '#app',
data: {
news: [{
title: 'Test Title',
url: '/test-title'
}]
},
methods: {
addItem: function(e) {
e.preventDefault(); // prevent page refresh
this.news.push({
"title": this.itemTitle,
"url": this.itemUrl
});
this.itemTitle = this.itemUrl = '';
}
}
});