How to exclude an element from an array? - javascript

I have a v-for to display all my categories. I would like to exclude a category, this category has an id = 1. So basically how can I remove by Id ? or maybe how can I exclude the first element of the array ? what do I do ?
<div class="list" v-for="(category,index ) in Categories" :key="category.id">

Use computed property component option.
computed: {
filteredCategories: function(){
//example ids to ignore
var ignore = [1, 10];
return this.categories.filter(cat => ignore.indexOf(cat.id) === -1);
}
}
<div class="list" v-for="(category,index ) in filteredCategories" :key="category.id">

You can use v-if.
<div class="list" v-for="(category,index ) in Categories" :key="category.id">
<template v-if="category.id === 1">
...

To get all categories with an id greater than 1, the cleanest way would be to have a filteredCategories computed:
<div class="list" v-for="category in filteredCategories" :key="category.id" />
computed: {
filteredCategories: {
return this.Categories.filter(cat => cat.id > 1);
}
}
Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
el: '#app',
data: () => ({
Categories: [
{id: 1, name: 'I won\'t get rendered!'},
{id: 2, name: 'Second category'},
{id: 3, name: 'Third category'},
{id: 4, name: 'Fourth category'},
{id: 0, name: 'I won\'t get rendered, either. My id is `0`'}
]
}),
computed: {
filteredCategories() {
return this.Categories.filter(cat => cat.id > 1);
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<div id="app">
<div class="list" v-for="category in filteredCategories" :key="category.id">
{{category.id}} - {{ category.name }}
</div>
</div>
The advantages are:
the initial Categories array is not mutated, so if you use it anywhere else in the component it will still contain all categories (which is not true if you filter using .splice)
the filtering is done based on the value of id, not on the category position in the array.
Here's how to get the Categories from the api:
data: () => ({
Categories: []
}),
computed: {
filteredCategories() {
return this.Categories.filter(cat => cat.id > 1);
}
},
mounted() {
axios.get("path/to/your/api")
.then(response => this.Categories = response.data);
}

Related

How to create a pipe in angular to filter array of objects with embedded array

Please, I have an array of object which embeds another array. I want to display with just a card that contains the item(s) filtered. Please check my illustration below.
Thank you
const customerList = [
{
id: 1,
customer: 'Rachel Stone',
items: ['Sardines', 'Milk', 'Custard', 'Egg']
},
{
id: 2,
customer: 'John Bull',
items: ['Vegetable Oil', 'Bread','Egg']
},
{
id: 3,
customer: 'Tega Paul',
items: ['sugar', 'milk', 'butter']
},
]
I created the filter in a pipe
transform(list: any[], filterText: string): any {
return list.map(x => {
x.items ? x.items.filter((item: string) => item.search(new RegExp(filterText, 'i')) > -1) : [];
})
}
I used the pipe here as follows;
<div *ngFor="let order of orders | searchFilter: searchTerm ">
<app-item-card
[customer]="order.customer"
[items]="order.items"
>
</app-item-card>
<button >
Order
</button>
</div>
The items card
<div>
<div> {{ customer }}</div>
<div >
<ul>
<li *ngFor="let item of items">{{ item }}</li>
</ul>
</div>
</div>
It was blank. All I want to do is if I type custard, it should display only a card where custard appears.
I am just learning angular/JavaScript/TypeScript. I will appreciate if any one can help.
your pipe not returning anything... you need to return data from the pipe.
check this stackblitz project or below code
transform(list: any[], filterText: string): any {
if (filterText) {
return list.map((x) => {
return x.items
? {
items: x.items.filter((item: any) =>
item.toLowerCase().includes(filterText.toLowerCase())
),
customer: x.customer,
}
: { items: [], customer: x.customer };
});
} else {
return list;
}
}

Remove an array from computed reverse method Vuejs

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>

Vue: existing array, add click effect and set true?

I am trying my hands at Nuxt and having a problem that I can't seem to figure out.
The concept:
I am having two arrays, one called items and one called selectedItems. I loop through the array of items to showcase them, if I click them, I simply add them to the array of selectItems and if I click them again, then they are removed from the array. Now I also added a click variable which helps enable coloring in the text to showcase which are selected. I tried simplifying the example with array of [A,B,C] in the code snippet down below!
The problem:
Now in the page, you will already have existing items in the selectedItems like in my example code, whereas [B] already exists in the array. Now how would I on a pageload, set the objects in the array SelectItems, in this case B to have already been clicked? I tried doing a comparing of the items in array Item and array selectedItem via a computed and then a if statement on the component for a class. This worked sorta EXCEPT the element wasn't actually clicked, so you would have to click TWICE in order for the object to be removed in the array. So how do I make the objects from selectedItem be click=true?
Vue.component('Item', {
template: `
<div>
<div :class="{'clicked': clicked,}" #click="selectItem()">
{{item.name}}
</div>
</div>
`,
props: {
item: {
type: Object,
default: null,
},
},
data() {
return {
clicked: false,
}
},
methods: {
selectItem() {
this.clicked = !this.clicked
const clickedItem = this.item
const id = clickedItem.id
if (this.clicked === true) {
this.$emit('add-item', clickedItem)
} else {
this.$emit('remove-item', id)
}
},
},
})
new Vue({
el: '#demo',
data() {
return {
items: [{id: 1, name: 'a'}, {id: 2,name: 'b'}, {id: 3, name: 'c'}],
selectedItems: [{id: 2, name: 'b'}],
}
},
methods: {
addItemToArray(clickedItem){
this.selectedItems = [...this.selectedItems, clickedItem]
},
removeItemFromArray(id){
this.selectedItems = this.selectedItems.filter(
(clickedItem) => clickedItem.id !== id
)
},
}
})
.clicked {background-color: coral;}</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<template>
<div v-for="item in items" :key="item.id">
<Item :item="item" #add-item="addItemToArray"
#remove-item="removeItemFromArray"> </Item>
</div>
</template>
</div>
The code:
https://stackblitz.com/edit/nuxt-starter-cxakbv?file=pages/index.vue
You can try this way:
In index you pass selectedItems to Item component:
<Item :item="item" :selectedItems="selectedItems" #add-item="addItemToArray"
#remove-item="removeItemFromArray"> </Item>
In Item component add new property selectedItem:
selectedItems: {
type: Array,
default: null,
},
And in mounted hook you check is item in selectItems array:
mounted() {
if (this.selectedItems.some(item => item.id === this.item.id)) this.clicked = true
}
Vue.component('Item', {
template: `
<div>
<div :class="{'clicked': clicked,}" #click="selectItem()">
{{item.name}}
</div>
</div>
`,
props: {
item: {
type: Object,
default: null,
},
selecteditems: {
type: Array,
default: null,
},
},
data() {
return {
clicked: false,
}
},
methods: {
selectItem() {
this.clicked = !this.clicked
const clickedItem = this.item
const id = clickedItem.id
if (this.clicked === true) {
this.$emit('add-item', clickedItem)
} else {
this.$emit('remove-item', id)
}
},
},
mounted() {
if (this.selecteditems.some(item => item.id === this.item.id)) this.clicked = true
}
})
new Vue({
el: '#demo',
data() {
return {
items: [{id: 1, name: 'a'}, {id: 2,name: 'b'}, {id: 3, name: 'c'}],
selectedItems: [{id: 2, name: 'b'}],
}
},
methods: {
addItemToArray(clickedItem){
this.selectedItems = [...this.selectedItems, clickedItem]
},
removeItemFromArray(id){
this.selectedItems = this.selectedItems.filter(
(clickedItem) => clickedItem.id !== id
)
},
}
})
.clicked {background-color: coral;}</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<template>
<div v-for="item in items" :key="item.id">
<Item :item="item" :selectedItems="selectedItems" #add-item="addItemToArray"
#remove-item="removeItemFromArray"> </Item>
</div>
</template>
</div>

Nested loops and to keep the index count going in the second one

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++}}

How to filter async computed data in Vuejs

I'm using asyncComputed in a Vuejs 2 app, and I need to filter a list of items that I'm fetching from an api.
This is what I have so far:
<template>
<div class="items">
<input type="text" v-model="searchKey">
<li v-for="item in items">
<span>{{item.name}}</span>
</li>
</div>
</template>
<script>
import Items from '#/api/items';
export default {
name: 'items',
data: {
searchKey: ''
}
asyncComputed: {
items: {
async get() {
const items = await Items.getAll();
return items.data;
},
default: []
}
},
methods: {},
components: {}
}
</script>
In this situation, is it possible to use a filter with the pipe operator, or do I need to create an entirely new filtered list and use that instead, like:
computed: {
filteredItems: function() {
return this.items.filter( ( item ) => item.name.toLowerCase().includes( this.searchKey.toLowerCase() );
}
}
Also, if I need to create a new filtered list, how can I do that with asynchronous data?
You can do it without any of the plugins, like this:
<template>
<div class="items">
<input type="text" v-model="searchKey">
<select v-model="filterType">
<option disabled value="">FilterBy</option>
<option>name</option>
<option>id</option>
</select>
<li v-for="item in filteredItems">
<span>{{item.name}}</span>
</li>
</div>
</template>
<script>
import Items from '#/api/items';
export default {
name: 'items',
data: {
searchKey: '',
items: null,
filterType:''
}
methods: {
async fetchItems(){
const items = await Items.getAll();
this.items = Items.data;
}
},
computed: {
filteredItems(){
if(this.filterType === 'name'){
return this.items.filter( ( item ) => item.name.toLowerCase().includes( this.searchKey.toLowerCase() );
}
if(this.filterType === 'id'){
return this.items.filter( ( item ) => item.id.includes( this.searchKey );
}
if(!this.filterType){
return this.items;
}
}
},
created(){
this.fetchItems();
}
}
</script>
You can even use a select input to select the criteria by which the list is to be filtered, in this case by id or by name.

Categories

Resources