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>
Related
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>
I got two nested loops and I'm trying to increment a counter in the second one, so basically that the count does not reset.
now: 1 2 3 4 1 2 3 4
want: 1 2 3 4 5 7 8
In vanila javascript I would have a variable but how is it done in Vue land?
EDItI want the count in the template not the javascript part.
new Vue({
el: "#app",
data: () => ({
todos: [],
activeIndex: -1
}),
mounted() {
for (let t of ['first', 'second']) {
const listObjects = []
for (let i = 0; i < 10; i++) {
listObjects.push({
url: `/${t}/${t}-${i}`,
name: `${t}-${i}`,
type: t
})
}
this.todos.push({
type: t,
listItems: listObjects
})
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<template v-for="todo of todos">
<ul>
<li
v-for="(item, i) of todo.listItems"
:class="{ 'item--is-active': activeIndex === i }">
{{ item.name }}
</li>
</ul>
</template>
</div>
new Vue({
el: "#app",
data: () => ({
todos: [],
activeIndex: -1,
counter: 0,
}),
mounted() {
for (let t of ['first', 'second']) {
const listObjects = []
for (let i = 0; i < 10; i++) {
listObjects.push({
url: `/${t}/${t}-${i}`,
name: `${t}-${i}`,
id: ++this.counter,
type: t
})
}
this.todos.push({
type: t,
listItems: listObjects
})
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<template v-for="todo of todos">
<ul>
<li
v-for="(item, i) of todo.listItems"
:class="{ 'item--is-active': activeIndex === i }">
{{ item.name }} id: {{ item.id }}
</li>
</ul>
</template>
</div>
I do not know Vue but I think you need something like:
mounted() {
let i = 0;
for (let t of ['first', 'second']) {
const listObjects = []
for (; i < 10; i++) {
listObjects.push({
url: `/${t}/${t}-${i}`,
name: `${t}-${i}`,
type: t
})
}
this.todos.push({
type: t,
listItems: listObjects
})
}
}
Define a variable outside of both loops and increment it inside the second.
If you want tthe variable to be reactive, declare the variable on the data object
data () {
return {
loopCounter: 0,
todos: []
}
}
Notice that I declared data as a method returning an object. This way all the instances of a component have their own data object and not share one. In your case, a vue instance, is not a problem, but in general you should declare it as a method and not an object.
Edit:
You could save the info on each listItem and print it from there instead of computing it on the spot.
You could use a data for loop count that you increment it inside the loop
{{loopCounter++}}
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 vue.js item in my page that tracks changes made to a form. It looks like this:
var changes_applied = [];
var changes_applied_block = new Vue({
name: "ChangesApplied",
el: '#changes-applied',
data: {
items: changes_applied
},
methods: {
remove: function(index) {
changes_applied.splice(index, 1);
}
}
});
When a change is detected the change is pushed onto the changes_applied array, and it shows up in the "Changes Applied" div as expected. The deletes also work, which just calls the remove method on the vue object.
I also have a "clear" button that's not connected to the vue instance, and when it's clicked it sets the data source back to an empty array using changes_applied = [];
The problem is that after this is cleared using the button, the changes / additions to the changes array no longer show up in the vue element-- it's like the vue element is no longer attached to the changes_applied array.
Am I missing a binding or something here that needs to happen, or is there a "vue way" to clear the vue data without touching the actual source array?
You shouldn't be changing the changes_applied array; Vue isn't really reacting to changes on that array. It only sort of works when this.items is pointed to the same array reference. When you change that reference by reassigning changes_applied it breaks because you are then manipulating changes_applied but it is not longer the same array as this.items.
You should instead be manipulating this.items directly:
methods: {
remove: function(index) {
this.items.splice(index, 1);
}
To clear it you can set:
this.items = []
and it will work as expected.
Your items array is initialized with changes_applied but does not mantaing bindings, it's just the default value for items when the instance is created. So if you change the changes_applied this will not affect the items array on vue instance.
example
new Vue({
el: '#app',
data: function () {
return {
items: myArr,
newItem: ''
}
},
methods: {
addItem () {
this.items.push(this.newItem)
this.newItem = ''
},
remove (index) {
this.items.splice(index, 1)
},
clear () {
this.items = []
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<input type="text" v-model="newItem" />
<button #click="addItem">Add</button>
<button #click="clear">Clear</button>
<p v-for="(item, index) in items" #click="remove(index)">{{item}}</p>
</div>
<!-- from outside vue instance-->
<button onClick="clearFromOutside()">clear from outside</button>
<script>
var myArr = ['hola', 'mundo'];
function clearFromOutside() {
console.log(myArr)
myArr = [];
console.log(myArr)
}
</script>
Mark_M already provided a good explanation, I'll add a demo, since I think its easier to understand how it works.
You can copy the value of the array to data, but then all operations must be done to the data directly:
const changes_applied = [
{id: 1},
{id: 2},
{id: 3}
];
const vm = new Vue({
el: '#app',
data: {items: changes_applied},
methods: {
add() {
const id = this.items.length + 1
this.items.push({id})
},
remove() {
this.items.pop()
},
clear() {
this.items = []
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<div>
<button type="button" #click="add">Add</button>
<button type="button" #click="remove">Remove</button>
<button type="button" #click="clear">Clear</button>
</div>
<ul name="list">
<li v-for="item in items" :key="item.id">
Item {{ item.id }}
</li>
</ul>
</div>
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>