3

I am using a computed property to filter through an array of values and pull out only a set of unique items from within the array. Originally I only needed it for one variable but I need to use it to pull two different values now and can't get it to work independently of each other when making two computed properties.

Here's my Vue HTML code:

<div v-for="item in getUniques">
<input :value="item.car" v-model="selectedCars" type="checkbox">
<label>&nbsp;{{item.car}}</label>
</div>

Here's the function:

 data(){
      return {

selectedCars: [],
prefetch: [
           {car: "XC90", brand: "Volvo"},
           {car: "XC60", brand: "Volvo"},
           {car: "XC90", brand: "Volvo"},
           {car: "X-Type", brand: "Jaguar"}   
          ]
 }
},


computed: {

getUniques(){

                return this.prefetch.reduce((seed, current) => {

                    return Object.assign(seed, {
                        [current.car]: current
                    });

                }, {});

            },

}


// This works perfectly for pulling out the unique values of cars and returns... [XC90,XC60, X-Type] 

But when I try to create another computed property to do the same, but only work with brands, everything breaks and I get undefined. How can I tweak this computed property so I can filter out all the other unique values in this array?

I've tried everything and can't work it out. Thanks in advance for any help!!

5
  • so replacing [current.car] with [current.brand] gives you an error? Commented Dec 19, 2019 at 20:13
  • it doesn't if I run it independently, but when I try to run them both at the same time as computed it throws an error. I know it's not recommended to add logic into computed properties, so I am stuck at figuring out where to go from there Commented Dec 19, 2019 at 20:15
  • I am interested though as to why this happens. I dont believe .reduce()does anything odd with the prefetch object but apparently it breaks when multiple computed properties use the same object? Commented Dec 19, 2019 at 20:20
  • Correct. Switching over to a map function as recommended by @Daniel below actually did the trick in order to run several computed properties at the same time. I would still love to find out if there's a way to stream along a single computed property rather than have to maintain several single map functions as the size of the sample array grows Commented Dec 19, 2019 at 20:28
  • Computed properties cache their output. They create a dependency list based on the content, and will only re-compute if a perceived dependency has changed. Two things you can try - 1) make the unique property more visible. This may turn out to be a bit hacky. 2) return a function which takes the unique property name, in this case the function is cached but works properly each time it's called. This may be done more simply as a method, rather than a computed property. Commented Dec 19, 2019 at 20:50

2 Answers 2

4

For the basic check for uniques

For an array like:

let prefetch = [
  {car: "XC90", brand: "Volvo"},
  {car: "XC60", brand: "Volvo"},
  {car: "XC90", brand: "Volvo"},
  {car: "X-Type", brand: "Jaguar"}   
 ]

You could use 2 the filter function as stated here: Get all unique values in a JavaScript array (remove duplicates)

let prefetch = [
  {car: "XC90", brand: "Volvo"},
  {car: "XC60", brand: "Volvo"},
  {car: "XC90", brand: "Volvo"},
  {car: "X-Type", brand: "Jaguar"}   
 ]

 function getUniqueCars() {
   return prefetch.map(x => x.car).filter((v,i,s) => s.indexOf(v) === i)
 }

 function getUniqueBrands() {
  return prefetch.map(x => x.brand).filter((v,i,s) => s.indexOf(v) === i)
 }

 console.log(getUniqueCars())
 console.log(getUniqueBrands())

This also works as a computed function within vue...

A solution for vue using a temporary Array

Another solution could be the creation of a temporary Array to calculcate the unique car/brand pairs you want to use...

let vm = new Vue({
  el: '#app',
  data() {
    return {
      selectedCars: [],
      prefetch: [{
          car: "XC90",
          brand: "Volvo"
        },
        {
          car: "XC60",
          brand: "Volvo"
        },
        {
          car: "XC60",
          brand: "Volvo"
        },
        {
          car: "XC90",
          brand: "Volvo"
        },
        {
          car: "X-Type",
          brand: "Jaguar"
        }
      ]
    }
  },
  computed: {
    getUniques() {
      let tempArray = [];
      for (let item of this.prefetch) {
        (tempItem => {
          if (!(tempItem.length > 0 && tempItem.find(x => x.brand === item.brand))) tempArray.push(item);
        })(tempArray.filter(x => x.car === item.car))
      }
      return tempArray;
    }
  }
})
<div id="app">
  <div v-for="item in getUniques">
    <input :value="item.car" v-model="selectedCars" type="checkbox">
    <label>&nbsp;{{item.brand}} {{item.car}}</label>
  </div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

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

4 Comments

Thanks! this works. However, I would still like to find out if there is a way to reduce the amount of functions by making everything into a single computed property since the array I'm working with is quite large
I (without refactoring) would build a tempArray to calculate uniques like function getUniques() { let tempArray = []; for(let item of prefetch) { (tempItem => { if(!(tempItem.length > 0 && tempItem.find(x => x.brand === item.brand))) tempArray.push(item); })(tempArray.filter(x => x.car === item.car)) } return tempArray; }
This last comment might work ok as a single computed - why don't you add it to the answer body for a bit more clarity, and show how the template uses it?
@RichardMatsen Thanks for the advice. I've added another solution using the temporary Array.
0

you can use lodash's uniq

and do

return _.uniqBy(this.prefetch, 'car');

3 Comments

See Computed Caching vs Methods, this may not help.
@RichardMatsen unless I'm misundertanding his question, the cached version should be fine? I'm still a little unclear on what his uniqueness criteria is though
Indeed, I'm confused about the final pattern al2xs wants to see. Note he needs the use car and brand plus other criteria in the future. The unique value must be seen as a reactive dependency, so a string literal does not qualify. Setting car in a separate data property would do the trick, but it's a bit noisy and difficult to implement in the template. A method is a better way, since methods do not cache.

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.