While rewriting my VueJs project in typescript, I came across a TypeScript error.
This is a part of the component that has a custom v-model.
An input field in the html has a ref called 'plate' and I want to access the value of that. The @input on that field calls the update method written below.
Typescript is complaining that value does not exist on plate.
@Prop() value: any;
update() {
this.$emit('input',
plate: this.$refs.plate.value
});
}
template:
<template>
<div>
<div class="form-group">
<label for="inputPlate" class="col-sm-2 control-label">Plate</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="inputPlate" ref="plate" :value="value.plate" @input="update">
</div>
</div>
</div>
</template>
You can do this:
class YourComponent extends Vue {
$refs!: {
checkboxElement: HTMLFormElement
}
someMethod () {
this.$refs.checkboxElement.checked
}
}
From this issue: https://github.com/vuejs/vue-class-component/issues/94
Updating this answer because Vue 3 (or the composition API plugin if you're using Vue 2) has some new functions.
<template>
<div ref="root">This is a root element</div>
</template>
<script lang="ts">
import { ref, onMounted, defineComponent } from '@vue/composition-api'
export default defineComponent({
setup() {
const root = ref(null)
onMounted(() => {
// the DOM element will be assigned to the ref after initial render
console.log(root.value) // <div>This is a root element</div>
})
return {
root
}
}
})
</script>
The vue-property-decorator
library provides @Ref which I recommend instead of my original answer.
import { Vue, Component, Ref } from 'vue-property-decorator'
import AnotherComponent from '@/path/to/another-component.vue'
@Component
export default class YourComponent extends Vue {
@Ref() readonly anotherComponent!: AnotherComponent
@Ref('aButton') readonly button!: HTMLButtonElement
}
None of the above answers worked for what I was trying to do. Adding the following $refs property wound up fixing it and seemed to restore the expected properties. I found the solution linked on this github post.
class YourComponent extends Vue {
$refs!: {
vue: Vue,
element: HTMLInputElement,
vues: Vue[],
elements: HTMLInputElement[]
}
someMethod () {
this.$refs.<element>.<attribute>
}
}
This worked for me: use
(this.$refs.<refField> as any).value
or (this.$refs.['refField'] as any).value
son.vue
const Son = Vue.extend({
components: {},
props: {},
methods: {
help(){}
}
...
})
export type SonRef = InstanceType<typeof Son>;
export default Son;
parent.vue
<son ref="son" />
computed: {
son(): SonRef {
return this.$refs.son as SonRef;
}
}
//use
this.son.help();
Avoid using bracket < >
to typecast because it will conflict with JSX.
Try this instead
update() {
const plateElement = this.$refs.plate as HTMLInputElement
this.$emit('input', { plate: plateElement.value });
}
as a note that I always keep remembering
Typescript is just Javascript with strong typing capability to ensure type safety. So (usually) it doesn't predict the type of X (var, param, etc) neither automatically typecasted any operation.
Also, another purpose of the typescript is to make JS code became clearer/readable, so always define the type whenever is possible.
Maybe it will be useful to someone. It looks more beautiful and remains type support.
HTML:
<input ref="inputComment" v-model="inputComment">
TS:
const inputValue = ((this.$refs.inputComment as Vue).$el as HTMLInputElement).value;
In case of custom component method call,
we can typecast that component name, so it's easy to refer to that method.
e.g.
(this.$refs.annotator as AnnotatorComponent).saveObjects();
where AnnotatorComponent is class based vue component as below.
@Component
export default class AnnotatorComponent extends Vue {
public saveObjects() {
// Custom code
}
}
With Vue 3 and the Options API, this is what worked for me:
<script lang="ts">
import {defineComponent} from 'vue';
export default defineComponent({
methods: {
someAction() {
(this.$refs.foo as HTMLInputElement).value = 'abc';
},
},
});
</script>
The autocomplete doesn't bring the foo
property from $refs
because it's defined in the template, and apparently there's no information inferred from it.
However, once you force the casting of .foo
to the HTML element type, everything works from there on, so you can access any element property (like .value
, in the example above).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With