Home > other >  Enable loading state of an input field on a computed property
Enable loading state of an input field on a computed property

Time:01-19

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"

  • Related