Vue js: function remove not working properly in my code - javascript

i have code below in Vue js that shows Categories from API and whenever i click on any of them it add it to the array AddCategory and post it to API, also i've implemented button Removeall that whenever i click on it, it remove all the selected categories in array (it will empty the array) and it works fine. my problem is when i want to click again on the selected single category (in function remove below) it's not poping it up from array however it pushed it twice, any help?
<template>
<b-row class="categories-row">
<div
class="categories"
v-for="(category, index) in categories"
:key="index"
#click="Add(category._id, index)"
:class="[selectedIndex.includes(index) ? 'green' : 'gray']"
required
>
{{ category.category_name }}
</div>
</b-row>
</template>
export default {
data() {
return {
categories: [],
selectedIndex: [],
AddCategory: [],
posts: {
description: null,
questionTitle: null,
categories: null,
},
};
},
methods: {
Add(AddCategory, index) {
if (this.selectedIndex.includes(index))
this.Remove(index);
else
this.selectedIndex.push(index);
this.AddCategory.push(AddCategory);
},
Remove(index) { //not working
this.selectedIndex.splice(this.selectedIndex.indexOf(index),1);
},
RemoveAll() {
this.AddCategory = [];
this.selectedIndex.splice(this.AddCategory);
},}}

try this:
Remove(index) {
this.selectedIndex = this.selectedIndex.filter((item)=> item !== index) ;
}
Edited:
#sara97 maybe you need remove it from this.AddCategory too.
Edited:
#sara97 and because it runs "this.AddCategory.push(AddCategory);" everytime. use {} in if and else.
Add(AddCategory, index) {
if (this.selectedIndex.includes(index)) {
this.Remove(AddCategory,index);
}else{
this.selectedIndex.push(index);
this.AddCategory.push(AddCategory);}
},
Remove(AddCategory,index) {
this.selectedIndex = this.selectedIndex.filter((item)=> item !== index);
this.AddCategory = this.AddCategory.filter((item)=> item !== AddCategory)
},

Related

Bootstrap Vue Checkbox <b-table> <b-form-checkbox>

I am trying to use b-form-checkbox with b-table. Trying to retrieve the selected module Ids.
<b-table
id="module-table"
:items="list.modules"
:fields="fields"
:busy="isBusy">
<template slot="num" slot-scope="row">
{{ row.index + 1 }}
</template>
<template slot="checkbox" slot-scope="row">
<b-form-group>
<b-form-checkbox v-if="!isLoading" v-model="row.item.selected" #change="selection(row.item.moduleId)" variant="outline-secondary" class="mr-1">
</b-form-checkbox>
</b-form-group>
</template>
</b-table>
data: {
fields: [
{ key: 'checkbox', label: '', class: 'd-none d-lg-table-cell' },
{ key: 'num', label: 'Num', class: 'd-none d-lg-table-cell' },
],
selected: []
}
Though I am able to retrieve the selected module Ids but unable to delete them while switching the checkboxes. If anyone can provide an idea on how to track if the checkbox is selected (true) or not selected (false). Thanks in advance.
methods: {
selection(item) {
if (true)
app.selected.push(item);
else
app.selected = app.selected.map(x => x != item);
}
},
The checkbox values are already stored in list.modules[].selected via the v-model, so you could just use a computed prop to get the selected modules instead of using a separate selected array:
Remove the #change="selection(⋯)" from <b-form-checkbox>:
<!--
<b-form-checkbox
v-model="row.item.selected"
#change="selection(row.item.moduleId)" // remove
>
-->
<b-form-checkbox
v-model="row.item.selected"
>
Remove the selection method and selected data property, since they're no longer needed.
export default {
data() {
return {
// selected: [] // remove
}
},
methods: {
// selection() {⋯} // remove
}
}
Add a computed prop that filters list.modules[] for selected modules:
export default {
computed: {
selected() {
return this.list.modules.filter(module => module.selected)
},
},
}
demo

Vuetify Autocmplete with data loaded dynamically

I got 60k items in my autocomplete form, so I wanted to load it after user types 3 characters with only items that contains the given characters. Is there an option in autocomplete to implement this?
You should rather filter this amount of data on server side.
But it is doable in Vuetify. You can use search-input.sync and computed property for filtering items. Then you should clear your search value by input method
<v-autocomplete
:value="value"
:items="filterdItems"
#input="clearSearch"
:search-input.sync="search"
/>
export default {
data() {
return {
value: null,
search: "",
items: [], // Your items
};
},
computed: {
filterdItems() {
if (this.search.length < 2) return;
return this.items.filter(item => item.startsWith(this.search))
}
}
methods: {
clearSearch() {
this.search = '';
},
},
};

How to display dynamically array on input value change?

I have a div in which I am displaying components from array of objects. Above the div I have an input[type=text] which will be filtering the displayed data depending what I will insert. It looks like that:
<div class="filters">
<input type="search" placeholder="Szukaj specjalisty"
:onchange="filterAllSpecialists">
<FilterData/>
</div>
<div class="all-fields">
<SpecialistPreview class="specialist-preview"
v-for="(talk, index) in newTalks"
:key="index"
:name="talk.name"
:speciality="talk.speciality"
:hourly-price="talk.hourlyPrice"
:half-hour-price="talk.halfHourPrice"
:avatar="talk.avatar"
:rating="talk.rating"
:is-available="talk.isAvailable"
>{{ talk }}
</SpecialistPreview>
</div>
I have created a method that takes the value of input and compares with the name from newTalks array:
<script>
export default {
data() {
return {
talks: [
{
name: 'Małgorzata Karwacka-Lewandowska',
speciality: 'Coach',
hourlyPrice: 150,
halfHourPrice: 80,
avatar: 'patrycja.jpg',
rating: 2.5,
isAvailable: true
},
... more objects
],
newTalks: []
}
},
methods: {
filterAllSpecialists(e) {
let input = e.target.value;
if (input !== '') {
this.newTalks = this.talks.filter(el =>
el.name.toLowerCase().includes(input.toLowerCase()))
console.log(this.newTalks);
return this.newTalks;
} else {
return this.newTalks;
}
}
},
mounted() {
this.newTalks = this.talks;
}
}
All I get is Uncaught SyntaxError: Function statements require a function name in the console
Since nobody answered and I have spent more time figuring out what was wrong with my code I found out that the first mistake I did was instead of using # I used : before onchange (I decided that for my purpose I needed #keyup instead of #change). Also there was an easier way of targeting the input value - simply by adding a v-model='allSpecialistInput.
So now in the template it should look like that:
<div class="filters">
<input type="search" placeholder="Szukaj specjalisty" v-model="allSpecialistsInput"
#keyup="filterAllSpecialists">
<FilterData/>
</div>
<div class="all-fields" v-cloak>
<SpecialistPreview class="specialist-preview"
v-for="(coach, index) in newCoaches"
:key="index"
:name="coach.name"
:speciality="coach.speciality"
:hourly-price="coach.hourlyPrice"
:half-hour-price="coach.halfHourPrice"
:avatar="coach.avatar"
:rating="coach.rating"
:is-available="coach.isAvailable"
>{{ coach }}
</SpecialistPreview>
</div>
In the methods all I needed to change was the first line in the filterAllSpecialists function like that:
filterAllSpecialists() {
let input = this.allSpecialistsInput; <--- here
if (input !== '') {
this.newCoaches = this.coaches.filter(el => el.name.includes(input.toLowerCase()))
return this.newCoaches;
} else {
return this.newCoaches;
}
},

Vue: How to use v-model in post ApI

I have code below in vue js and I wanted to update data the model by using AddCategory and it works fine, on the other hand, I wanted to post this to API Url using the post data below, but when I set v-model="posts.AddCategory" it didn't work, is there a way to do it?
<b-form-input
id="input"
type="text"
name="AddCategory"
v-model="AddCategory" //v-model="posts.AddCategory" didn't work
placeholder="categories"
required
/>
<div
class="categories"
v-for="(category, index) in categories"
:key="index"
#click="Add(index, AddCategory)"
>
<mark> {{ category.category_name }} </mark>
<script>
export default {
name: "postComponent",
components: {
Editor: PrismEditor,
},
data() {
return {
categories: [],
selectedIndex: null,
isediting: false,
AddCategory: "",
posts: {
title: null,
question: null,
code: require("../example.js").default /* eslint-enable */,
},
};
},
methods: {
Add(AddCategory, index) {
this.AddCategory = AddCategory;
this.selectedIndex = index;
this.isediting = true;
},
Your v-model=posts.AddCategory won't work as you are hitting one of the object caveats as defined in vue https://v2.vuejs.org/v2/guide/reactivity.html#For-Objects.
What you can do is first in your Add method you could to so:
Add(category,index){
this.$set(this.post,'AddCategory',category);
....
}

Vue.js 2 - Selected item from a re-populated list is not refreshing changes

Given the following set of data in my vue.js 2 component:
data() {
return {
listItems: [{
id: '',
name: '',
subItems: []
}],
selectedItem: '',
hasSelectedItem: false
}
}
I'm filling up the listItems with a REST API and selecting a specific item in the view:
getItems() {
axios.get(this.base_url + '/items/all', {headers: {Authorization: "Bearer " + this.token}}).then(response => {
this.listItems = response.data
}).catch(e => {
this.errors.push(e)
});
},
Then at some point in the UI I select a specific item from listItems by something like this:
<el-dropdown size="medium" #command="handleCommand">
<el-button size="small" type="primary">
Select item<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<div v-for="(item) in listItems">
<el-dropdown-item :disabled="selectedItem === item"
:command="item">
{{ item.name }}
</el-dropdown-item>
</div>
<el-dropdown-item divided>
New Item
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
and the function:
handleCommand(selected) {
this.selectedItem = selected;
this.hasSelectedItem = true
}
The problem is that whenever I add new stuff into its subItems[] by a POST request to the server and call again the getItems() to refresh the listItems list, the selectedItem stays as before and doesn't refresh.
Shouldn't this be an assignment by reference?
What's the right way to do it?
Thanks in advance!
UPDATE 1
Maybe I should re-ask this in a different way:
If I have a list of items,
and in addition, I have a selectedItem reference to one of them,
what's the right way to update selectedItem on a member change from within the list?
You should avoid comparing object use
:disabled="selectedItem.id === item.id"
instead of
:disabled="selectedItem === item"
also in your data() method use selectedItem: {}
data() {
return {
listItems: [{
id: '',
name: '',
subItems: []
}],
selectedItem: {},
hasSelectedItem: false
}
}
Update
You are partially right about having selectedItem by reference, but when you get the list of items again from server you replace the list of items and loose the object reference as well. You can refresh the selectedItem after getting data from server like this :
getItems() {
axios.get(this.base_url + '/items/all', {
headers: {
Authorization: "Bearer " + this.token
}
}).then(response => {
this.listItems = response.data
if (this.selectedItem.id) {
this.selectedItem = this.listItems.find((item) => {
return item.id === this.selectedItem.id;
})
}
}).catch(e => {
this.errors.push(e)
});
},
Try binding :key with v-for.
<div v-for="(item) in listItems" :key="item">
<el-dropdown size="medium" #command="handleCommand">
<el-button size="small" type="primary">
Select item<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<div v-for="(item) in listItems" :key="item">
<el-dropdown-item :disabled="selectedItem === item"
:command="item">
{{ item.name }}
</el-dropdown-item>
</div>
<el-dropdown-item divided>
New Item
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>

Categories