How to refresh view when vuex store changes? - vue.js

I get the data from the store like so
computed: {
notes() {
var data = this.$store.getters.getNotes;
var key = this.$store.getters.getTitleFilter;
if (key === "all") return data;
return data.filter((note) => {
var filteredNote = note.category.some(({ name }) => name === key);
if (filteredNote) return filteredNote;
});
},
},
When the note array changes (an item is removed, getNotes should reflect that. In other instances (where the data is returned without filtering) this used to do the trick:
watch: {
notes(newval) {
return newval;
},
},
I there a way to get the filtered array to update?

Related

How to search inside an array property of an index

I have to retrieve a list of apps that have certain string inside of an array property:
const users = algoliaClient.initIndex('apps')
return users.search('myId123', { hitsPerPage: 50 });
The apps objects are just like this:
{categories: ['an', 'interesting', 'category']}
How can I search the index for items with a categories property that contains any item in an array of strings?
const search = ["cat1", "cat2", "cat3"];
const apps = [
{
name: "app1",
categories: ["cat1", "cat5"],
},
{
name: "app2",
categories: ["cat2", "cat4"],
},
];
is that what you mean ? if so :
var myIndexes = [];
apps.forEach((app, index) => {
search.every((search) => {
if (app.categories.includes(search)) {
myIndexes.push(index);
return false; // return false here is for stoping the EVERY loop
} else {
return true; // keep running the EVERY loop
}
});
});

Method to check if item is saved within the Nuxt Store

I currently have a Store that has the "Saved" items from a feed for a user. I'm trying to figure out the best/efficient way to check if the item is already saved within the store.
I can't think of any other way than grabbing the entire store's contents in each feed item and checking whether the id exists? Surely there's a better way?
FeedItem.vue
methods: {
savePost(Post) {
this.$store.commit('savedPosts/addItem', Post)
},
deletePost(Post) {
this.$store.commit('savedPosts/removeItem', Post)
}
}
Store
export const state = () => ({
items: [
],
})
export const mutations = {
updateItemsOnLoad(state, array) {
var oldItems = state.items
var newItems = array.flat()
var joinedItems = newItems.concat(oldItems);
state.items = joinedItems.flat()
},
addItem(state, item) {
state.items.push(item)
this.$warehouse.set('savedPosts', state.items)
},
removeItem(state, item) {
var index = state.items.findIndex(c => c.id == item.id);
state.items.splice(index, 1);
this.$warehouse.set('savedPosts', state.items)
},
}
So my main question: Is there a more efficient way to check whether a post exists within the items array without querying it on every feed item?

TypeError: Cannot read properties of undefined (reading 'products')

I am trying to get products, then check if the product pId is in an array, and filter if it is.
I get an error when i soft refresh of 'TypeError: Cannot read properties of undefined' (reading 'products'), almost like my 'this.products' isnt populated yet when computed is trying to get the data. Tried adding some if statements to check data is there but no luck.
<script>
export default {
data() {
return {
popular_products: [],
products: [],
}
},
computed: {
bestsellers() {
const keywords = this.popular_products
let array = []
for (var index = 0; index < keywords.length; index++) {
const keyword = this.products.data.products.product.filter(
(product) => product.pId == keywords[index].ProductNumber
)
array = array.concat(keyword)
}
return array
},
},
mounted() {
axios
.get(
'https://myurl/admin/api/collections/get/popularproducts?token=account-9306f9192049d3c442e565f2de5372'
)
.then((response) => (this.popular_products = response.data.entries))
axios
.get('https://myurl/products.json')
.then((response) => (this.products = response))
},
}
</script>
The problem is with this line:
let keyword = this.products.data.products.product.filter(product => product.pId == keywords[index].ProductNumber);
more specific with this read: data.products.
You see, computed property bestsellers is evaluated before your axios calls are finished.
Because of that, Vue can't find products in data because your this.products doesn't have data key.
The best solution would be to change this assignment:
- .then(response => (this.products = response)); // delete this line
+ .then(response => (this.products = response.data.products)); // add this line
Update After comment.
if (this.products.product) {
return this.products.product.filter(...)
} else {
return []
}

Duplicate items in list after an API update

I'm learning vuejs and I'm doing a weather app, the goal is to rank cities with an index (humidex). I fetch weather information by API (axios) in order to collect data from several cities. I want to auto update data every x minutes, problem : some of my results are duplicated (the new data don't replace the old one).
I tried to set an unique key (based on latitude and longitude) for each item, it works for several results but not for all.
data () {
return {
items:[],
show: false,
cities: cities,
newCity:''
}
},
components: {
Item
},
computed: {
sortHumidex() {
return this.items.slice().sort((a,b) => {
return this.getHumidex(b) - this.getHumidex(a) || b.current.temp_c - a.current.temp_c
})
}
},
methods: {
addCity() {
if (this.newCity.trim().length == 0) {
return
}
this.cities.push(this.newCity)
this.newCity = ''
},
getHumidex: (el) => {
const e = 6.112 * Math.pow(10,(7.5*el.current.temp_c/(237.7+el.current.temp_c)))
*(el.current.humidity/100)
return Math.round(el.current.temp_c + 5/9 * (e-10))
},
indexGeo: (e) => {
const lat = Math.round(Math.abs(e.location.lat))
const lon = Math.round(Math.abs(e.location.lon))
return lat.toString() + lon.toString()
},
getApi: function () {
const promises = [];
this.cities.forEach(function(element){
const myUrl = apiUrl+element;
promises.push(axios.get(myUrl))
});
let self = this;
axios
.all(promises)
.then(axios.spread((...responses) => {
responses.forEach(res => self.items.push(res.data))
}))
.catch(error => console.log(error));
}
},
created() {
this.getApi()
this.show = true
}
}
The render when I update API :
By pushing to the existing array of items, you have to deal with the possibility of duplicates. This can be eliminated simply by replacing items every time the API call is made.
Replace:
responses.forEach(res => self.items.push(res.data))
with:
self.items = responses.map(res => res.data)

FlatList single select cell

I followed the example from official docs, here is how to implement multiselection feature:
state = { selected: (new Map(): Map<string, boolean>) };
onPressItem = (id) => {
this.setState((state) => {
const selected = new Map(state.selected);
selected.set(id, !selected.get(id));
return { selected };
});
};
I'm struggling with making it single select though. It's easy to return new Map with false values anytime cell is tapped, but that means the cell cannot be deselected by another tap on it, which is the desired feature in my case.
onPressItem = (id) => {
this.setState((state) => {
const selected = new Map();
selected.set(id, !selected.get(id));
return { selected };
});
};
How would you implement it? Should I use lodash to iterate over the Map to find the one that already is true and change its value (now sure how to iterate over Map though), or maybe there is some better approach I am missing right now?
EDIT
Iterating over elements of the selected Map seems to be a really ugly idea, but it is simple and it actually works. Is there any better way to do it that I am missing out on?
onPressItem = (id: string) => {
this.setState((state) => {
const selected = new Map(state.selected);
selected.set(id, !selected.get(id));
for (const key of selected.keys()) {
if (key !== id) {
selected.set(key, false);
}
}
return { selected };
});
};
Thanks in advance
You can just set only one value instead of a map like this
onPressItem = (id) => {
this.setState((state) => {
const selected = selected === id ? null : id;
return { selected };
});
};
I had the same issue, my solution was:
_onPressItem = (id: string) => {
// updater functions are preferred for transactional updates
this.setState((state) => {
// copy the map rather than modifying state.
const selected = new Map(state.selected);
// save selected value
let isSelected = selected.get(id);
// reset all to false
selected.forEach((value, key) => {
selected.set(key, false);
});
// then only activate the selected
selected.set(id, !isSelected);
return { selected };
});
};