VUEJS remove Element From Lists? - vue.js

it is possible to remove specific element from lists. i tried this functions for remove element
pop() = remove last element
$remove(index) = not remove any element from lists
remove( index ) = undefined function
unshift( index ) = add new and empty element
splice( index ) = remove all element from index
please help me to remove specific element from lists.
below is my js code
var example2 = new Vue({
el: '#example-2',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' },
{ message: 'Bar1' },
{ message: 'Bar2' },
{ message: 'Bar3' },
{ message: 'Bar4' }
]
},
methods : {
removeElement : function(index){
this.items.$remove(index);
}
}
})
below is my HTML code
<ul id="example-1">
<li v-for="(key, item) in items">
{{ item.message }}
<button v-on:click="removeElement(key)">remove</button>
</li>
</ul>

$remove is deprecated in Vue.js 2.0 and replaced by splice as stated in the docs. Make sure you add the 2nd parameter of splice for it to work.
Migration From Vue 1.x - 2.0
methods: {
removeElement: function (index) {
this.items.splice(index, 1);
}
}

You can use Vue.delete if your Vue version is 2.2.0+
Vue.delete(this.items, index);

The $.remove feature has been replaced with $.delete.
You can call it like so:
this.$delete(this.someItems, itemIndex).
It works on Object as well as Array. With objects, you need to use a keyed object. With arrays, you pass in the index of the item you want to delete.
Here is a fiddle example: https://jsfiddle.net/james2doyle/386w72nn/
EDIT
I added an example for an array as well

$delete can use inline in #click:
<ul id="example">
<li v-for="(item, key) in items">
{{ item.message }}
<button #click="$delete(items, key)">remove</button>
</li>
</ul>
https://v2.vuejs.org/v2/api/#vm-delete

Firstly, you should fix the methods key.
Then, you should pass the item to the $remove method, not the index. [ref]
https://jsfiddle.net/790og9w6/

If anyone wonders: $delete has been removed in VueJS 3 ( https://v3-migration.vuejs.org/breaking-changes/introduction.html#removed-apis ). Now it is possible to use javascripts native splice(index, count of objects to be deleted).

Related

Why are checkboxes not reset by v-model?

This is what i have:
Template
<div
v-for="(filter, index) in filtersList"
:key="index"
class="option-block"
>
<label
v-for="value in filter.values"
:key="value.id"
class="option-block__container"
>
{{ value.title }}
<input
type="checkbox"
v-model="filtersValues[filter.name]"
:value="value.value"
>
<span class="option-block__checkmark"></span>
</label>
</div>
And the part of my vue code:
data() {
return {
filtersList: {},
filtersValues: {}
}
},
beforeMount() {
this.loadInitData();
this.initFilters();
},
methods: {
loadInitData() {
const data = JSON.parse(this.$el.getAttribute('data-data'));
this.filtersList = data.filters;
},
initFilters() {
for (let i in this.filtersList) {
if (!this.filtersList.hasOwnProperty(i)) {
continue;
}
this.filtersValues[this.filtersList[i].name] = [];
}
}
}
It works, but when i call initFilters() method again (for reseting) checkboxes are still selected, and i don't know why.
The way you are assigning new, empty arrays to filterValues is not reactive.
If you change your initFilters to assign an entire new value to filterValues, you don't need to worry about using Vue.set(). For example
initFilters() {
this.filtersValues = this.filtersList.reduce((vals, { name }) => ({
...vals,
[ name ]: []
}), {})
}
Demo ~ https://jsfiddle.net/cjx09zwt/
Where did filter.values come from in line 2 of template?
Anyways vue would not be able to track the changes you are making (judging from the visible code)
There are some caveats to vue 2's reactivity. Check here for more info.
TLDR; you will need to declare anything you want to be made reactive in the component's data option upfront.
HTH

Why v-for item not reactive and not changed?

Why name 2 not changed and not reactive? What wrong?
How can I make it reactive so that when the properties of the object change, the DOM also changes?
When I delete Name 2 nothing happens
<template>
<div>
<div v-for="(item, index) in items" v-bind:key="item.id">
<p>{{item.name}}</p>
</div>
<button v-on:click="deleteItem">
Delete Name 2
</button>
</div>
</template>
<script>
export default {
data:function(){
return {
items:[
{
id: 1,
name: "Name 1"
},
{
id: 2,
name: "Name 2"
}
]
}
},
methods: {
deleteItem: function(){
this.items[1] = [];
console.log(this.items);
alert("DELETED");
}
},
created: function(){
let self = this;
setTimeout(function(){
self.items[1] = [];
}, 2000);
}
};
</script>
the reactivity in vue (2) is a little bit tricky, this link explain you how to solve this issue
https://v2.vuejs.org/v2/guide/reactivity.html#For-Arrays
Modify your delete item function. Don't set it to an empty array. Filter the array like this:
Your HTML Markup :
<button #click="deleteItem(2)">
Delete Name 2
</button>
Send the id of the item that you want to delete to the deleteItem() as an argument.
deleteItem: function(itemId){
let filtered = this.items.filter((each) => {
return each.id !== itemId;
})
this.items = filtered; //Finally mutate the items[] in data
}
You are actually assigning an empty array to item with index 1, instead of removing it.
If you want to remove the element with index 1 simply use splice() and Vue will automatically react to it:
this.items.splice(1, 1); // The first 1 is the index
Or, alternatively use Vue.delete(), which is originally to remove properties from object, but can also remove items from arrays:
Vue.delete(this.items, 1); // 1 is the index
More info: https://v2.vuejs.org/v2/api/#Vue-delete

VueJs/Nuxt Filter an array, error _vm.filtered.. is not a function

I am new to Vue/Nuxt and try to filter an array.
computed: mapState({
entries: state => state.archives.archives
}),
filteredArchive, function (objects, key) {
if (objects) {
return objects.filter(function(object) {
return object.tag === key
})
}
I want to get the result in a loop:
<li v-for="(entry, index) in (entries | filteredArchive('test'))">{{ entry.title }}</li>
This fails..
What is wrong in my approach..
Thanks for help.
I suggest creating a computed property for "filteredArchive" instead of a filter. In fact, I believe filters are going away in Vue 3. You can put it in a mixin if you need to share the logic across components.
ok. this is my solution for now:
<ul>
<li v-for="(entry, index) in filteredByTag(entries, 'test')">
<nuxt-link :to="'archive/' + entry.id">{{ entry.title }}</nuxt-link>
</li>
</ul>
computed: mapState({
entries: state => state.archives.archives,
}),
methods: {
filteredByTag(entries, tag){
return entries.filter((entry) => {
return entry.tag.match(tag)
})
}
},

Can I insert a computed property into a Vue component dynamically

I am generating the contents of a Vue component by iterating through a large array of objects. I'd like to use computed properties to determine whether to show certain nodes, but since the computed reference is used inside a loop, I need to be able to set the reference name dynamically.
Below is a notional example of what I'm trying to do. How can I make showItemX change based on the current item?
<template>
<ul>
<li v-for="item in myArr" v-if="showItemX">
{{ item.name }}
</li>
</ul>
</template>
<script>
export default {
data() {
return {
myArr: [{
id: 'item1',
name: 'Item 1'
}, {
id: 'item2',
name: 'Item 2'
}]
};
},
computed: {
showItem1: function() {
return this.$store.state.showItem1;
},
showItem2: function() {
return this.$store.state.showItem2;
}
}
}
</script>
2 possible solutions
These are the two routes I've considered so far, but I'm not sure which one would be more efficient or if another way would be preferred:
1. Return a single object for the computed property
In this option, the two computed properties above would be combined into a single property:
computed: {
showItem: function() {
return {
item1: this.$store.state.showItem1,
item2: this.$store.state.showItem2
}
}
}
Then the the v-if would be set to showItem[item.id]:
<li v-for="item in myArr" v-if="showItem[item.id]">
{{ item.name }}
</li>
The downside here is that it seems that the entire object gets recomputed each time one of the dependencies changes.
2. Use a method to get the corresponding computed property
Here I tried passing item.id to a method as a way to access the corresponding computed property:
computed: {
item1Show: function() {
return this.$store.state.showItem1;
},
item2Show: function() {
return this.$store.state.showItem2;
}
},
methods: {
showItem: function(id) {
return this[id + 'Show']
}
}
And in the template:
<li v-for="item in myArr" v-if="showItem(item.id)">
{{ item.name }}
</li>
Again, in this example, I'm not sure if I'm fully leveraging the computed properties.
Should one of these options be preferred over the other or is there a better way to accomplish this that I'm missing?
The nice thing about Vue and JavaScript is that you can use whichever approach suits your needs, but, fwiw, I'd probably find something like the following easiest to understand
<li v-for="item in myArr" v-if="showItem(item)">
{{ item.name }}
</li>
And then define the showItem method, e.g.
showItem(item) {
return item.id === "item1" ?
this.$store.state.showItem1 :
this.$store.state.showItem2;
}
That assumes you're not using the computed properties anywhere else not shown in the post
There's a better way.
For possible solution #1, you might as well do
<li v-for="(item, index) in myArr" v-if="$store.state['showItem' + (index + 1)]">
Possible solution #2, you completely miss out on Vue's optimizations.
The method, while not computationally intensive, will re-run for every element each render.
Below is a solution which fits the specific parameters of your example problem. However, it's not actually what I recommend here. More below.
<template>
<ul>
<!--
`:key` is crucial for performance.
otherwise, every element will re-render
whenever the filtered array updates.
-->
<li v-for="item in myFilteredArr" :key="item.id">
{{ item.name }}
</li>
</ul>
</template>
<script>
export default {
data: _ => ({
myArr: [
{
id: 'item1',
name: 'Item 1'
},
{
id: 'item2',
name: 'Item 2'
}
],
}),
computed: {
myFilteredArr () {
/*
abstracting state to a constant avoids
re-running the getter functions each iteration
*/
const state = this.$store.state;
return this.myArr.filter(
(item, index) => state['showItem' + (index + 1)]
);
}
}
}
</script>
My actual recommendation is that you move all this logic into a Vuex getter. You can read about them here: https://vuex.vuejs.org/guide/getters.html .
Since your filtering logic is already being processed in the store, the function which is setting all the showItem's can just be cut and pasted into a Vuex getter, returning myFilteredArr in the same way as above.
This way, there's no component<->store interdependency, and your store's state will be much cleaner.

VueJS - pass data to component with existing row

Here's my fiddle
data: {
address_components: [
{ id:1, city_id:1, area_id: 100}
],
city_id:0,
area_id:0,
sort:1
},
I need to pass data to existing row, is that incorrect?
And if I add a new row, the id should be '2'
like this
what is the good way to do this? :'-(
modify your code like this:
addComponent() {
this.address_components.push({id:++this.sort})
},
How about creating a list in your data() and just push a object there.
<ul id="example-1">
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
var example1 = new Vue({
el: '#example-1',
data: {
items: []
},
methods:
{
Add:function()
{
//process the inputs and push it to items list
this.items.push({ message: "Hi"})
}
}
})
Did not tested this and just created from example from Vue Documentation but you got the idea. Pushing a new item in list will automatically updates the component or the element