0

I have a simple application where a user selects a value from a dropdown list and when they click on the "add" button that value and its id should be populated into an array using the id as an index.

Example:

Values


1 - Apple
3 - Bananas 8 - Pears

User selects each fruit, clicking add after each selection. My array should look like this:

 [
    1: Apple,
    3: Bananas,
    8: Pears
 ]

However what I end up with in Vue is this:

[
    1: Apple,
    2: undefined,
    3: Bananas,
    4: undefined,
    5: undefined,
    6: undefined,
    7: undefined,
    8: Pears
]

These values are being passed as input to server validation and obviously this is creating a problem with array length and validation rules. How can I remove these undefined values or prevent Vue from populating them in the first place?

user1347026
  • 588
  • 1
  • 8
  • 14

2 Answers2

2

Vue isn't inserting undefined into your array. That's just the behavior of JavaScript arrays (i.e., sparse arrays).

A quick solution to get a new array of the defined elements is to use Array.prototype.filter:

const input = [
  'Apple',
  undefined,
  'Bananas',
  undefined,
  undefined,
  undefined,
  undefined,
  'Pears'
];
const output = input.filter(x => x); // filter out undefined elements
console.log(output)
tony19
  • 125,647
  • 18
  • 229
  • 307
0

Arrays are always contiguous; any "holes" in the array will be filled with undefined.

What you want to use instead is an object:

{
  data() {
    return {
      items: {}
    }
  },

  methods: {
    add(id, item) {
      // Vue cannot detect property additions, so we must use
      // this method to do so
      this.$set(this.items, id, item)
    }
  }
}

If you render out the items of this object in the template with v-for, the order will typically be the same as the order in which each item was added to the object (see v-for with an Object). If you require the items to be rendered in ID order, then you need to sort the items:

<div v-for="item of itemsArray">{{ item }}</div>
computed: {
  itemsArray() {
    return Object.entries(this.items)
      .sort((a, b) => a[0] - b[0])  // sort entry key (ID)
      .map(a => a[1])  // take entry value
  }
}
tony19
  • 125,647
  • 18
  • 229
  • 307
Decade Moon
  • 32,968
  • 8
  • 81
  • 101