1

Basically, this code is responsible to display into a dropdown the list of cars name contained inside the sortedCars array. (This array is sorted by string asc).

Now, I added an input text, and I'm trying to filter automatically the list of cars matching with the entered name value.

With the following code, the UI is never updated. Where is the mistake ?

<template>
        <div class="btn-group pull-left">
            <input type="text" @keyup="onFilterCars" v-model="searchCarTextValue" />
            <a v-for="car in this.sortedCars" :key="car.name" @click="onSelectCategoryFilterLabel" class="dropdown-item" href="#">
                <span v-else>{{ car.name }}</span>
            </a>
        </div>
</template>

<script>
export default {
    data() {
        return {
            inputFilterText: "",
            mapFilteringEnabled: false,
            searchCarTextValue: ""
        };
    },
    props: {
        cars: {
            type: Array
        }
    },
    computed: {

        sortedCars: function() {

            function compare(a, b) {

                if (a.name < b.name)
                    return -1;
                if (a.name > b.name)
                    return 1;

                return 0;
            }

            var sortedArr = this.cars.sort(compare);

            return sortedArr;
        }

    },
    methods: {

        onFilterCars() {
            if (this.searchCarTextValue) {
                var arrayFiltered = this.sortedCars.filter( (car) => {
                    return car.name.toLowerCase().indexOf(this.searchCarTextValue.toLowerCase()) != -1
                });
                this.sortedCars = arrayFiltered;
            }
        }

    }
};
</script>
4
  • one note:this.sortedCars changes every time, so after a while it contains nothing, instead you should save the list of all cars somewhere else and filter from that list without altering it, so effecticvely have two lists one with all cars and one filtered Commented Dec 19, 2019 at 12:25
  • computed property will automatically recompute when its dependent properties change. You dont need the onFilterCars handler at all. Commented Dec 19, 2019 at 12:31
  • you have div" twice....not the answer but a problem Commented Dec 19, 2019 at 12:31
  • and a span v-else without an v-if Commented Dec 19, 2019 at 12:35

2 Answers 2

3

in vue it is easy to filter, usually i take an approach like this:

<template>
<div>
    <div" class="btn-group pull-left">
        <input type="text" v-model="filters.searchCarTextValue" />
    </div">
</div>
</template>

<script>
export default {
{
    data(){
        return {
            filters:{
                searchCarTextValue: ''
            }
        }
    },
    props: {
        cars: {
            type: Array
        }
    },
    computed: {
        // returns list of cars based of filters
        filtered_cars(){
            let vm = this;
            if(!vm.filters.searchCarTextValue){
                return [];
            }
            return vm.sortedCars.filter(car => {
                return car.name.toLowerCase().indexOf(vm.filters.searchCarTextValue.toLowerCase()) != -1
            })
        },
        sortedCars: function() {

            function compare(a, b) {

                if (a.name < b.name)
                    return -1;
                if (a.name > b.name)
                    return 1;

                return 0;
            }

            var sortedArr = this.cars.sort(compare);

            return sortedArr;
        }
    }
}
</script>

This way there is no need to use a method to filter, since the computed will change whenever filters.searchCarTextValue or sortedCars changes. So you also won't need a button to trigger the filtering.

working example: https://jsfiddle.net/rmfbpLk9/2/

Sign up to request clarification or add additional context in comments.

Comments

1

There was several bugs in the code as people stated in the comments, i've fixed all those, and changed around your method to a computed, and removed all the places where you actually were settings variables and computed declarations wrong.

Working sandbox: https://codesandbox.io/s/musing-feather-10isg

Code:

<template>
  <div>
    <div class="btn-group pull-left">
      <input type="text" v-model="searchCarTextValue">
      <a
        v-for="car in this.filteredCars"
        :key="car.name"
        @click="onSelectCategoryFilterLabel"
        class="dropdown-item"
        href="#"
      >
        <span>{{ car.name }}</span>
      </a>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      inputFilterText: "",
      mapFilteringEnabled: false,
      searchCarTextValue: ""
    };
  },
  props: {
    cars: {
      type: Array
    }
  },
  computed: {
    filteredCars() {
      function compare(a, b) {
        if (a.name < b.name) return -1;
        if (a.name > b.name) return 1;

        return 0;
      }

      let cars = this.cars.filter(car => {
        return (
          car.name
            .toLowerCase()
            .indexOf(this.searchCarTextValue.toLowerCase()) != -1
        );
      });

      cars.sort(compare);

      return cars;
    }
  },
  methods: {
    onSelectCategoryFilterLabel() {
      console.log("OK");
    }
  }
};
</script>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.