[Vuejs]-Vue – check if a :key has already been used in v-for

1👍

Rather than trying to query Vue internals, just add a unique prefix for each context.

<div v-for a in b :key='`loop1_${a.id}`' />
<div v-for a in b :key='`loop2_${a.id}`' />

If you want to track keys conditionally, you will need to collect them by hand; The keys are not exposed by the public Vue API.

<div v-for a in b :key='getKey(a)' />

// data

const keys = {}

// methods 

getKey(o) {
  keys[o.id] = true
  return o.id;
}

hasKey(id) {
  return !!keys[id]
}
if (hasKey(object.id)) {
    // don't add the object to the array
} else {
    // add the object to the array
}

If you dare to go into the internals:

https://github.com/vuejs/vue/blob/e90cc60c4718a69e2c919275a999b7370141f3bf/dist/vue.runtime.common.dev.js

function checkDuplicateKeys (children) {
    var seenKeys = {};
    for (var i = 0; i < children.length; i++) {
      var vnode = children[i];
      var key = vnode.key;
      if (isDef(key)) {
        if (seenKeys[key]) {
          warn(
            ("Duplicate keys detected: '" + key + "'. This may cause an update error."),
            vnode.context
          );
        } else {
          seenKeys[key] = true;
        }
      }
    }
  }

3👍

Use a computed property and filter your data by unique id.

For example:

//
var vm = new Vue({
  el: '#app',
  data() {
    return {
      values: [{
        id: 1,
        value: '1'
      }, {
        id: 1,
        value: '1'
      }, {
        id: 2,
        value: '2'
      }, {
        id: 3,
        value: '3'
      }, {
        id: 3,
        value: '3'
      }, {
        id: 4,
        value: '4'
      }]
    }
  },
  computed: {
    unique_values: function() {
      const result = []
      const map = new Map()
      for (const item of this.values) {
        if (!map.has(item.id)) {
          map.set(item.id, true)
          result.push(item)
        }
      }
      return result
    }
  }
});
<div id="app">
  <table style="width:100%;text-align:left">
    <thead>
      <tr>
        <th>index</th>
        <th>id</th>
        <th>value</th>
      </tr>
      <thead>
        <tbody>
          <tr v-for="(row, index) in unique_values" :key="index">
            <td>{{ index }}</td>
            <td>{{ row.id }}</td>
            <td>{{ row.value }}</td>
          </tr>
        </tbody>
  </table>
</div>

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

Leave a comment