EDITED: code pen was added at the end of the post
How to eanable (change to true) the loading of an input field in a computed property?
In the example for demonstration that follows I get the 'error' unexpected side effect in "inputFilterParentsAndChilds" computed property.
The search field and the list
<template>
<q-input
label="Search"
v-model="searchValue"
placeholder="Minimum 3 characters"
:loading="loadingState"
/>
<q-list
v-for="pater in inputFilterParentsAndChilds"
:key="pater.id_parent"
>
<q-item>
<q-item-section>
<q-item-label>
{{ pater.name }}
</q-item-label>
</q-item-section>
</q-item>
<q-list
v-for="filius in pater.allfilius"
:key="filius.id_filius"
>
<q-item>
<q-item-section>
<q-item-label>
{{ filius.title }}
</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-list>
</template>
Computed propriety
<script>
export default {
data() {
return {
loadingState: false,
searchValue: ''
};
}
}
computed: {
//filter the parent list with nested data (childs)
inputFilterParentsAndChilds() {
if (this.searchValue.length > 2) {
this.loadingState = true; // error!! unexpected side effect in "inputFilterParentsAndChilds" computed property
const filteredPaterArr = this.records.map((rows) => {
const filteredParent = rows.filius.filter(
({ name }) =>
name.toLowerCase().match(this.searchValue.toLowerCase())
);
const filteredChilds = rows.filius.filter(
({ title }) =>
title.toLowerCase().match(this.searchValue.toLowerCase())
);
if (filteredChilds.length) {
this.loadingState = false;
return { ...rows, filius: filteredParent };
} else {
this.loadingState = false;
return { ...rows, filius: filteredChilds };
}
});
return filteredPaterArr.filter((obj) => obj.filius.length);
} else {
return this.records;
}
}
}
</script>
About nested v-for list Filter nested v-for list
EDITED
CODEPEN https://codepen.io/ijose/pen/BaYMVrO
Why is loading important in my case?
If the list has hundreds of records the filter is slow and appears (wrongly) to have frozen, requiring a loading to inform the user that the filtering operation is still in progress
CodePudding user response:
You don't, computed properties simply can't change state.
You can achieve similar effects by watching searchValue.
data () {
return {
searchValue: '',
isLoading: false,
filteredElements: []
}
},
watch: {
searchValue: {
immediate: true, // tells Vue to run handler function right after constructing the component
handler () {
// this function will be triggered when searchValue changes
this.isLoading = true
// give Vue chance to render the loader before doing heavy computation in 'filterElements' function
this.$nextTick(() => {
this.filteredElements = this.filterElements()
this.isLoading = false
})
}
}
Docs on nextTick Docs on watchers
Edit: Have you measured that it's really computing that makes your drop-down slow and not rendering? Take a look at the documentation on performance, especially "Virtualizing large lists"