Good day, how to remove an array from a reverse method?
Here's my code
const app = Vue.createApp({
data() {
return {
app_title: 'Simple Checklist App',
entered_task_value: '',
list_of_tasks: [],
is_priority: false,
}
},
computed: {
reverseItems() {
return [...this.list_of_tasks].reverse();
}
},
methods: {
add_item() {
this.list_of_tasks.push(
{
id: this.list_of_tasks.length + 1,
data: this.entered_task_value,
priority: this.is_priority,
}
);
this.entered_task_value = '';
this.is_priority = '';
},
total_tasks() {
return this.list_of_tasks.length;
},
remove_item(task_index) {
return this.reverseItems.splice(task_index, 1);
}
},
});
app.mount('#app');
The remove_item method is not working and I am not sure how to properly call the property inside the computed
remove_item(task_index) {
return this.reverseItems.splice(task_index, 1);
}
This is the HTML
<ul>
<li
v-for="(task, task_index) in reverseItems"
class="item"
:key="task.id"
:class="{priority: task.priority}"
>
{{task.id}}
{{task.data}}
<button v-on:click="remove_item(task_index)">Remove</button>
</li>
</ul>
Thank you in Advance!
You should update the list_of_tasks of task array instead of the computed array.
The computed values are calculated from the real data and updated each time the data changes.
Here is the documentation about computed properties in vue.js
Here is a small example
new Vue({
el: '#app',
data: () => {
return {
myArr: [1,2,3,4,5]
}
},
computed: {
myArrReversed(){
return [...this.myArr].reverse()
}
},
methods : {
addItem(){
this.myArr.push(this.myArr.length +1)
},
removeItem(){
this.myArr.splice(this.myArr.length - 1, 1)
},
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul>
<li v-for="item of myArrReversed" :key='item'>
{{item }}
</li>
</ul>
<button #click="addItem">Add item</button>
<button #click="removeItem">Remove item</button>
</div>
Related
The search is working properly. The main problem occurs when I want to delete it but the previous numbers won't be back. In this code, I'm applying the changes directly to the main variable but I shall not. What is the way?
new Vue({
el: '#app',
data() {
return {
list: [],
search: '',
}
},
mounted() {
for(let i = 1300; i <= 1400; i++) {
const _n = i.toString()
this.list.push(_n)
}
},
methods: {
handleSearch() {
this.list = this.list.filter(i => i.includes(this.search));
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input #input="handleSearch()" v-model="search" placeholder="search number" />
<ul>
<li v-for="(item, i) in list" :key="i">{{item}}</li>
</ul>
</div>
The issue happens because you nested filter the same list, but you need to have a list with full items and another list with filtered items, and iterate on the filtered items, not the main list.
I suggest you use computed property with the filtered list, instead of firing input event because you already use v-model to control the input
new Vue({
el: '#app',
data() {
return {
list: [],
search: '',
}
},
mounted() {
for(let i = 1300; i <= 1400; i++) {
const _n = i.toString()
this.list.push(_n)
}
},
computed: {
filteredList() {
return this.list.filter(i => i.includes(this.search));
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input v-model="search" placeholder="search number" />
<ul>
<li v-for="(item, i) in filteredList" :key="i">{{item}}</li>
</ul>
</div>
YOu have list where you filter the items and overwrite list with the new filtered result.
When you move a char, you apply same same on list, but those items were already removed right? No way to get them back.
Use a second list, originalList that you will use to filter, but do not overwrite so you can always refer to the original values
Vue.config.devtools = false;
new Vue({
el: '#app',
data() {
return {
list: [],
originalList: [],
search: '',
}
},
mounted() {
for(let i = 1300; i <= 1400; i++) {
this.originalList.push(i.toString())
}
this.list = [ ...this.originalList ];
},
methods: {
handleSearch() {
this.list = this.originalList.filter(i => i.includes(this.search));
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input #input="handleSearch()" v-model="search" placeholder="search number" />
<ul>
<li v-for="(item, i) in list" :key="i">{{item}}</li>
</ul>
</div>
I want to create an autocomplete component, so I have the following code.
<Input v-model="form.autocomplete.input" #on-keyup="autocomplete" />
<ul>
<li #click="selected(item, $event)" v-for="item in form.autocomplete.res">
{{item.title}}
</li>
</ul>
autocomplete(e){
const event = e.path[2].childNodes[4]
if(this.form.autocomplete.input.length > 2){
this.Base.get('http://localhost:3080/post/search/post', {
params: {
q: this.form.autocomplete.input
}
})
.then(res => {
this.form.autocomplete.res = res.data
if(this.form.autocomplete.res.length > 0)
event.style.display = 'block'
})
}
},
selected(item, e){
this.form.autocomplete.item = item
console.log(e)
}
however, how would I do to have the return after selecting my item in the main file?
Ex:
Home.vue
<Autocomplete :url="www.url.com/test" />
When selecting the item I want from my autocomplete, how do I get the return from it and store it in that file, as if I were using v-model?
As Vue Guide said:
Although a bit magical, v-model is essentially syntax sugar for
updating data on user input events, plus special care for some edge
cases.
Then at Vue Using v-model in Components,
the <input> inside the component must:
Bind the value attribute to a value prop
On input, emit its own custom input event with the new value
Then follow above guide, one simple demo will be like below:
Vue.config.productionTip = false
Vue.component('child', {
template: `<div>
<input :value="value" #input="autocomplete($event)"/>
<ul v-show="dict && dict.length > 0">
<li #click="selected(item)" v-for="item in dict">
{{item.title}}
</li>
</ul>
</div>`,
props: ['value'],
data() {
return {
dict: [],
timeoutControl: null
}
},
methods: {
autocomplete(e){
/*
const event = e.path[2].childNodes[4]
if(this.form.autocomplete.input.length > 2){
this.Base.get('http://localhost:3080/post/search/post', {
params: {
q: this.form.autocomplete.input
}
})
.then(res => {
this.form.autocomplete.res = res.data
if(this.form.autocomplete.res.length > 0)
event.style.display = 'block'
})
}*/
clearTimeout(this.timeoutControl)
this.timeoutControl = setTimeout(()=>{
this.dict = [{title:'abc'}, {title:'cde'}]
}, 1000)
this.$emit('input', e.target.value)
},
selected(item){
this.selectedValue = item.title
this.$emit('input', item.title)
}
}
})
new Vue({
el: '#app',
data() {
return {
testArray: ['', '']
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<child v-model="testArray[0]"></child>
<child v-model="testArray[1]"></child>
<div>Output: {{testArray}}</div>
</div>
I have a Modal component in my main app that gets passed content via an event whenever a modal has to be shown. Modal content is always a list with an action associated with each item, like "select" or "remove":
Vue.component('modal', {
data() {
return {
shown: false,
items: [],
callback: ()=>{}
}
},
mounted() {
EventBus.$on('showModal', this.show);
},
template: `<ul v-if="shown">
<li v-for="item in items">
{{ item }} <button #click="callback(item)">Remove</button>
</li>
</ul>`,
methods: {
show(items, callback) {
this.shown = true;
this.items = items;
this.callback = callback;
}
}
});
Sadly, when passing a computed property to that modal like in the component below, the reactive link gets broken -> if the action is "remove", the list is not updated.
Vue.component('comp', {
data() {
return {obj: {a: 'foo', b: 'bar'}}
},
computed: {
objKeys() {
return Object.keys(this.obj);
}
},
template: `<div>
<button #click="showModal">Show Modal</button>
<modal></modal>
</div>`,
methods: {
remove(name) {
this.$delete(this.obj, name);
},
showModal() {
EventBus.$emit('showModal', this.objKeys, this.remove);
}
}
});
See the minimal use case in this fiddle: https://jsfiddle.net/christophfriedrich/cm778wgj/14/
I think this is a bug - shouldn't Vue remember that objKeys is used for rendering in Modal and update it? (The forwarding of the change of obj to objKeys works.) If not, what am I getting wrong and how could I achieve my desired result?
You have the modal working with its own copy of items:
template: `<ul v-if="shown">
<li v-for="item in items">
{{ item }} <button #click="callback(item)">Remove</button>
</li>
</ul>`,
methods: {
show(items, callback) {
this.shown = true;
this.items = items;
this.callback = callback;
}
}
That copy is made once, upon the call to show, and what you are copying is just the value of the computed at the time you emit the showModal event. What show receives is not a computed, and what it assigns is not a computed. It's just a value.
If, anywhere in your code, you made an assignment like
someDataItem = someComputed;
the data item would not be a functional copy of the computed, it would be a snapshot of its value at the time of the assignment. This is why copying values around in Vue is a bad practice: they don't automatically stay in sync.
Instead of copying values around, you can pass a function that returns the value of interest; effectively a get function. For syntactic clarity, you can make a computed based on that function. Then your code becomes
const EventBus = new Vue();
Vue.component('comp', {
data() {
return {
obj: {
a: 'foo',
b: 'bar'
}
}
},
computed: {
objKeys() {
return Object.keys(this.obj);
}
},
template: `<div>
<div>Entire object: {{ obj }}</div>
<div>Just the keys: {{ objKeys }}</div>
<button #click="remove('a')">Remove a</button>
<button #click="remove('b')">Remove b</button>
<button #click="showModal">Show Modal</button>
<modal></modal>
</div>`,
methods: {
remove(name) {
this.$delete(this.obj, name);
},
showModal() {
EventBus.$emit('showModal', () => this.objKeys, this.remove);
}
}
});
Vue.component('modal', {
data() {
return {
shown: false,
getItems: null,
callback: () => {}
}
},
mounted() {
EventBus.$on('showModal', this.show);
},
template: `<div v-if="shown">
<ul v-if="items.length>0">
<li v-for="item in items">
{{ item }} <button #click="callback(item)">Remove</button>
</li>
</ul>
<em v-else>empty</em>
</div>`,
computed: {
items() {
return this.getItems && this.getItems();
}
},
methods: {
show(getItems, callback) {
this.shown = true;
this.getItems = getItems;
this.callback = callback;
}
}
});
var app = new Vue({
el: '#app'
})
<script src="//unpkg.com/vue#latest/dist/vue.js"></script>
<div id="app">
<comp></comp>
</div>
You are passing a value to a function, you are not passing a prop to a component. Props are reactive, but values are just values. You include modal in the template of comp, so rework it to take (at least) items as a prop. Then it will be reactive.
I would recommend having the remove process follow the emit-event-and-process-in-parent rather than passing a callback.
const EventBus = new Vue();
Vue.component('comp', {
data() {
return {
obj: {
a: 'foo',
b: 'bar'
}
}
},
computed: {
objKeys() {
return Object.keys(this.obj);
}
},
template: `<div>
<div>Entire object: {{ obj }}</div>
<div>Just the keys: {{ objKeys }}</div>
<button #click="remove('a')">Remove a</button>
<button #click="remove('b')">Remove b</button>
<button #click="showModal">Show Modal</button>
<modal :items="objKeys" event-name="remove" #remove="remove"></modal>
</div>`,
methods: {
remove(name) {
this.$delete(this.obj, name);
},
showModal() {
EventBus.$emit('showModal');
}
}
});
Vue.component('modal', {
props: ['items', 'eventName'],
data() {
return {
shown: false,
}
},
mounted() {
EventBus.$on('showModal', this.show);
},
template: `<div v-if="shown">
<ul v-if="items.length>0">
<li v-for="item in items">
{{ item }} <button #click="emitEvent(item)">Remove</button>
</li>
</ul>
<em v-else>empty</em>
</div>`,
methods: {
show(items, callback) {
this.shown = true;
},
emitEvent(item) {
this.$emit(this.eventName, item);
}
}
});
var app = new Vue({
el: '#app'
})
<script src="//unpkg.com/vue#latest/dist/vue.js"></script>
<div id="app">
<comp></comp>
</div>
I have a component in Vue that looks like this:
<template>
<div id="featured_top">
<i class="i-cancel close"></i>
<div v-for="item in toplist">
<div class="featured-item" v-lazy:background-image="poster(item)">
<a class="page-link" :href="url(item)" target="_blank">
<h4 class="type"> Featured Movie </h4>
<div class="title">{{ item.title }}</div>
</a>
</div>
</div>
</div>
</template>
<script>
const _ = require('lodash')
export default {
name: 'featured',
computed: {
toplist () {
return _.sampleSize(this.$store.state.toplist, 3)
}
},
methods: {
poster: function (item) {
return 'https://example.com/' + item.backdrop_path
},
url: function (item) {
return 'http://example.com/' + item.id
}
}
}
</script>
I choose three random items from the store hen rendering the component, iterate over and display then. However, this seems too static so I'd like periodically update the component so it randomises the items again.
I'm new to Vue2 - any ideas on what trivial bit I'm missing?
Your use-case is not completely clear to me but if you'd like to randomize with an interval. You could change your computation to a method and call this function with setInterval.
Something like in the demo below or this fiddle should work.
(In the demo I've removed the lazy loading of the image to reduce the complexity a bit.)
// const _ = require('lodash')
const testData = _.range(1, 10)
.map((val) => {
return {
title: 'a item ' + val
}
})
const store = new Vuex.Store({
state: {
toplist: testData
}
})
//export default {
const randomItems = {
name: 'featured',
template: '#tmpl',
computed: {
/*toplist () {
return _.sampleSize(this.$store.state.toplist, 3)
}*/
},
created() {
this.getToplist() // first run
this.interval = setInterval(this.getToplist, 2000)
},
beforeDestroy() {
if (this.interval) {
clearIntervall(this.interval)
this.interval = undefined
}
},
data() {
return {
interval: undefined,
toplist: []
}
},
methods: {
getToplist() {
this.toplist = _.sampleSize(this.$store.state.toplist, 3)
},
poster: function(item) {
return 'https://example.com/' + item.backdrop_path
},
url: function(item) {
return 'http://example.com/' + item.id
}
}
}
new Vue({
el: '#app',
template: '<div><random-items></random-items</div>',
store,
components: {
randomItems
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/2.1.1/vuex.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
<div id="app">
</div>
<script type="text/template" id="tmpl">
<div id="featured_top">
<i class="i-cancel close"></i>
<div v-for="item in toplist">
<div class="featured-item" v-lazy:background-image="poster(item)">
<a class="page-link" :href="url(item)" target="_blank">
<h4 class="type"> Featured Movie </h4>
<div class="title">{{ item.title }}</div>
</a>
</div>
</div>
</div>
</script>
How to use the computed to realize It? When I input in the input the ul only show the li which inclue my input. For example, if I am inputting the Ad, then only show the "Add some todos" li. And if I give up input, the ul will goback, all the li will show again.
This is my code, and I use Vue.
div id="app">
<input v-model="newTodo" v-on:keyup.enter="addTodo">
<ul>
<li v-for="todo in todos">
<span>{{ todo.text }}</span>
<button v-on:click="removeTodo($index)">X</button>
</li>
</ul>
<script>
new Vue({
el: '#app',
data: {
newTodo: '',
todos: [
{text: 'Add some todos'}
]
},
methods: {
addTodo: function () {
var text = this.newTodo.trim()
if (text) {
this.todos.push({text: text})
this.newTodo = ''
}
},
removeTodo: function (index) {
this.todos.splice(index, 1)
}
}
})
</script>
Define a computed to do the filtering you want done.
Use the computed instead of todos in your v-for.
new Vue({
el: '#app',
data: {
newTodo: '',
todos: [{
text: 'Add some todos'
}]
},
computed: {
filteredTodos: function() {
const re = new RegExp(this.newTodo, 'i');
return this.todos.filter((item) => re.test(item.text));
}
},
methods: {
addTodo: function() {
var text = this.newTodo.trim()
if (text) {
this.todos.push({
text: text
})
this.newTodo = ''
}
},
removeTodo: function(index) {
this.todos.splice(index, 1)
}
}
})
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script>
<div id="app">
<input v-model="newTodo" v-on:keyup.enter="addTodo">
<ul>
<li v-for="todo in filteredTodos">
<span>{{ todo.text }}</span>
<button v-on:click="removeTodo($index)">X</button>
</li>
</ul>
</div>