I want to create a component with Vue.js containing a label
and an input
. For example :
<label for="inputId">Label text</label>
<input id="inputId" type="text" />
How can I set a unique ID for each component instance?
I want to create a component with Vue.js containing a label
and an input
. For example :
<label for="inputId">Label text</label>
<input id="inputId" type="text" />
How can I set a unique ID for each component instance?
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.
ready
method was removed in Vue 2.0 and above. I was very confused when the ready
method wasn't executing. https://mcmap.net/q/137498/-vue-js-ready-function-is-not-triggered –
Heddi data
must be a function that returns an object: vuejs.org/v2/guide/components.html#data-Must-Be-a-Function –
Yajairayajurveda this._uid
is not valid. Instead, generate your id yourself, e.g. public id = uuid4();
, see uuid4. –
Ghislainegholston _uid
, it "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". –
Shindig declare module 'vue/types/vue' { interface Vue { _uid: any; } }
But don't use it. Also in combination with SSR _uid
and uuid4
are no options. –
Landers :id="id"
was very useful –
Microminiaturization 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;
},
};
I published the vue-unique-id Vue plugin for this on npm.
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 uidCounter = 0;
Vue.mixin({
beforeCreate: function() {
this.uidCounter = uidCounter.toString();
uidCounter += 1;
},
});
// Generate a component-scoped id
Vue.prototype.$id = function(id) {
return "uid-" + this.uidCounter + "-" + 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" />
uuid
was an unfortunate name choice so I've renamed it to uidCounter
. Javascript is single threaded so I don't see which race conditions could possibly creep in the code above. uidCounter
is read and updated atomically because no there are no other threads and execution isn't preempted. Imo, an actual UUID doesn't offer any benefit over a simple incrementing counter for this use-case, but yes it works. –
Individuate 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");
}
});
}
});
_uid
property does not exist anymore. –
Summitry 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
.
id
properties on elements. Also, -S
(or --save
) has been the default on npm
since 2017 and doesn't actually do anything any more. –
Ambulacrum For Vue.js v3 you can get id like this:
In template: {{ $.uid }}
In script: this.$.uid
Or use your own function or mix them:
this.componentUid = ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
);
This will return e.g:
aa174375-5b75-4919-acd0-980fcd54003c
The simplest way I found was to create a UUID (uuid package
) manually through a global mixin. That way you won't rely on anything that can potentially change or become deprecated in the future like this._uid
.
You first have to install the uuid
package:
npm i uuid
Then, in your main.js
file create a global mixin:
// rest of imports
import { v4 as uuidv4 } from 'uuid';
const app = Vue.createApp(App);
app.mixin({
data() {
return {
componentId: uuidv4()
}
},
});
app.use(store).use(router).mount('#app');
And here is how you can us it in a component:
<template>
<div>
<h1>{{ componentId }}</h1>
<button @click="printId()">click me for componentId.</button>
</div>
</template>
<script>
export default {
methods: {
printId: function() {
console.log(this.componentId);
}
}
}
</script>
This seem to work for me using in nuxtjs
https://www.npmjs.com/package/uuid
example of generated output: element: 47bfe557-d75f-455c-9a37-85b7935b297b
package.json
"dependencies": {
"uuid": "^8.3.2"
},
on child component, might not be the best way but seem to work
...
<ComponentName v-if="element" />
...
import { v4 as uuidv4 } from 'uuid';
...
data() {
return {
element: null,
}
}
...
mounted() {
this.element = uuidv4();
}
In Vue2, use v-bind
.
Say I have an object for a poll
<div class="options" v-for="option in poll.body.options">
<div class="poll-item">
<label v-bind:for="option._id" v-bind:style="{color: option.color}">
{{option.text}}
</label>
<input type="radio" v-model="picked" v-bind:value="option._id" v-bind:id="option._id">
</div>
</div>
v-for="(option, index) in poll.body.options"
, and use index
in you v-bind. –
Buiron A simple approach that I haven't seen in the replies is:
<template>
<div>
<label :for="id">Label text for {{id}}</label>
<input :id="id" type="text" />
</div>
</template>
<script>
import uniqueId from 'lodash-es/uniqueId'
export default {
computed: {
id () {
# return this._uid
return uniqueId('id')
}
}
}
</script>
If you're using TypeScript, without any plugin, you could simply add a static id in your class component and increment it in the created() method. Each component will have a unique id (add a string prefix to avoid collision with another components which use the same tip)
<template>
<div>
<label :for="id">Label text for {{id}}</label>
<input :id="id" type="text" />
</div>
</template>
<script lang="ts">
...
@Component
export default class MyComponent extends Vue {
private id!: string;
private static componentId = 0;
...
created() {
MyComponent.componentId += 1;
this.id = `my-component-${MyComponent.componentId}`;
}
</script>
class
-based syntax for defining Vue components? For example using `export default defineComponent({ created() { ... }, ... }); –
Bruce This package seems to be a good solution for the underlying issue of having non-unique IDs in your DOM across multiple components:
It is a trend to use components. Components are cool, they are small, obvious, easy to use and modular. Untill it comes to the id property.
Some HTML tag attributes requires using an id property, like label[for], input[form] and many of aria-* attributes. And the problem with the id is that it is not modular. If several id properties on the page will has the same value they can affect each other.
VueUniqIds helps you to get rid of this problem. It provides the set of id-related directives which value is automatically modified by adding unique string while keeping the attrbitue easy to read.
This seem to work for me using https://www.npmjs.com/package/uuid
example of generated output: element: 47bfe557-d75f-455c-9a37-85b7935b297b
package.json
"dependencies": {
"uuid": "^8.3.2"
},
component.vue
v-if="element"
...
import { v4 as uuidv4 } from 'uuid';
...
data() {
return {
element: null,
}
}
...
mounted() {
this.element = uuidv4();
}
According to MDN, you can just make an implicit label binding.
<label>
Label text
<input type="text" />
</label>
This way you don't even need to assign an id.
id
property, but this doesn't really answer the question. There are cases in which you can't avoid needing to use an id
. Also, MDN has a Vue tutorial (here) where they give an non-working example of how to set unique IDs on components... That's what brought me here. –
Ambulacrum for
attribute to explicitly associate labels with controls. –
Spondee If your uid is not used by other compoment, I have an idea.
uid: Math.random()
Simple and enough.
It can also be achieved using this pattern (Vue 2.0 v-bind) , so let say you have a list of items to iterate over and you want to give some dom element uninque id's.
new Vue({
el:body,
data: {
myElementIds : [1,2,3,4,5,6,8]
}
})
Html
<div v-for="id in myElementIds">
<label v-bind:for="id">Label text for {{id}}</label>
<input v-bind:id="id" type="text" />
<div>
Hope it helps
© 2022 - 2024 — McMap. All rights reserved.