I have a component which should pass everything on to the child. I'm successfully passing $attrs
and $listeners
already:
<template>
<el-form v-on="$listeners" v-bind="$attrs" :label-position="labelPosition">
<slot />
</el-form>
</template>
But I'm unsure how to also forward $refs
like we can do in React, so that when using my component like this:
<el-form-responsive
class="form"
:model="formValues"
status-icon
:rules="rules"
ref="form"
label-width="auto"
@submit.native.prevent="submitForm"
>
Then this.$refs.form
is actually a reference to the child <el-form>
.
I would rather do this transparently, as in you pass exactly the same props to el-form-responsive
as you would to a el-form
without needing to know that refs
has to be passed in a special way.
I have a component which should pass everything on to the child. I'm successfully passing $attrs
and $listeners
already:
<template>
<el-form v-on="$listeners" v-bind="$attrs" :label-position="labelPosition">
<slot />
</el-form>
</template>
But I'm unsure how to also forward $refs
like we can do in React, so that when using my component like this:
<el-form-responsive
class="form"
:model="formValues"
status-icon
:rules="rules"
ref="form"
label-width="auto"
@submit.native.prevent="submitForm"
>
Then this.$refs.form
is actually a reference to the child <el-form>
.
I would rather do this transparently, as in you pass exactly the same props to el-form-responsive
as you would to a el-form
without needing to know that refs
has to be passed in a special way.
4 Answers
Reset to default 6I don't think it is possible to directly mimic React's ref
. A ref
attribute in Vue is just a string which is used to register a child component reference to the parent's $refs
object during the render function.
Here are the links to documentations doc & doc
So basically it's a kind of inverted logic.. instead of passing a ref to a child in Vue we get it from the child into the parent. So it's not really possible at this point to create a grandchild reference, which is what you need.
There are some workarounds though.
1. Quick dirty and not transparent but technically it would work:
In the parent component, which uses your el-form-responsive
, on mounted
hook we could replace the original child reference with the grandchild ref.
Your el-form-responsive
component. Template:
<el-form ref="elform">
A parent which uses your el-form-responsive
. Template:
<el-form-responsive ref="form">
Script:
...
mounted () {
this.$refs.form = this.$refs.form.$refs.elform
}
And after this this.$refs.form
is actually a reference to the granchild <el-form>
2. This one would be more elaborate, but probably mach better then the first method:
In order to make the el-form-responsive
component really transparent you could expose some of the methods and properties from the child el-form
component to any potential parent. Something like this:
el-form-responsive
. Template:
<el-form ref="elform">
Script:
export default {
data: () => ({
whatever: null
}),
mounted () {
this.whatever = this.$refs.elform.whatever
},
methods: {
submit () {
this.$refs.elform.submit()
}
}
}
So then inside some parent el-form-responsive
could be used like this:
<el-form-responsive ref="form">
...
mounted () {
const formWhatever = this.$refs.form.whatever // actually `whatever` from `el-form`
this.$refs.form.submit() // eventually calls submit on `el-form`
},
If you are working with a custom component with the script setup
in Vue 3, it's worth nothing that template refs work like this.
Essentially, you will have to use defineExpose
to "expose" your child component data to the parent component
Try this to replace parent's ref with child's , In el-form-responsive
<template>
<el-form v-on="$listeners" v-bind="$attrs" :label-position="labelPosition" ref='ref'>
<slot />
</el-form>
</template>
mounted () {
Object.entries(this.$parent.$refs).forEach(([key, value]) => {
if (value === this) {
this.$parent.$refs[key] = this.$refs.ref
}
})
...
It is work for me:
mounted() {
Object.assign(Object.getPrototypeOf(this), this.$refs.formRef)
}
warning: insert to __proto__
,maybe is bad way