Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue.js : How to set a unique ID for each component instance?

Tags:

vue.js

Each component has a unique id which can be accessed as this._uid.

<template>
  <div>
    <label :for="id">Label text for {{id}}</label>
    <input :id="id" type="text" />
  </div>
</template>

<script>
export default {
  data () {
    return {
      id: null
    }
  }, 
  mounted () {
    this.id = this._uid
  }
}
</script>

If you want more control over the ids you can for example, generate them inside a parent component.


To Nihat's point (above): Evan You has advised against using _uid: "The vm _uid is reserved for internal use and it's important to keep it private (and not rely on it in user code) so that we keep the flexibility to change its behavior for potential future use cases. ... I'd suggest generating UIDs yourself [using a module, a global mixin, etc.]"

Using the suggested mixin in this GitHub issue to generate the UID seems like a better approach:

let uuid = 0;

export default {
  beforeCreate() {
    this.uuid = uuid.toString();
    uuid += 1;
  },
};

Update: Code will throw an error if ._uid property does not exist in the instance so that you can update it to use something custom or new unique id property if provided by Vue.

Although zxzak's answer is great; _uid is not a published api property. To save a headache in case it changes in the future, you can update your code with just one change with a plugin solution like below.

Vue.use({
    install: function(Vue, options) {
        Object.defineProperty(Vue.prototype, "uniqId", {
            get: function uniqId() {
                if ('_uid' in this) {
                   return this._uid;
                }
                throw new Error("_uid property does not exist");
            }
        });
    }
});

Update

I published the vue-unique-id Vue plugin for this on npm.

Answer

None of the other solutions address the requirement of having more than one form element in your component. Here's my take on a plugin that builds on previously given answers:

Vue.use((Vue) => {
  // Assign a unique id to each component
  let uuid = 0;
  Vue.mixin({
    beforeCreate: function() {
      this.uuid = uuid.toString();
      uuid += 1;
    },
  });

  // Generate a component-scoped id
  Vue.prototype.$id = function(id) {
    return "uid-" + this.uuid + "-" + id;
  };
});

This doesn't rely on the internal _uid property which is reserved for internal use.

Use it like this in your component:

<label :for="$id('field1')">Field 1</label>
<input :id="$id('field1')" type="text" />

<label :for="$id('field2')">Field 2</label>
<input :id="$id('field2')" type="text" />

To produce something like this:

<label for="uid-42-field1">Field 1</label>
<input id="uid-42-field1" type="text" />

<label for="uid-42-field2">Field 2</label>
<input id="uid-42-field2" type="text" />

npm i -S lodash.uniqueid

Then in your code...

<script>
  const uniqueId = require('lodash.uniqueid')

  export default {
    data () {
      return {
        id: ''
      }
    },
    mounted () {
       this.id = uniqueId()
    }
  }
</script>

This way you're not loading the entire lodash library, or even saving the entire library to node_modules.