8000 custom directives on components: Can't access child component in directive hooks. · Issue #2562 · vuejs/core · GitHub
[go: up one dir, main page]

Skip to content

custom directives on components: Can't access child component in directive hooks. #2562

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
zq8024 opened this issue Nov 5, 2020 · 16 comments

Comments

@zq8024
Copy link
zq8024 commented Nov 5, 2020

Version

3.0.2

Reproduction link

https://codesandbox.io/s/weathered-resonance-d2f6t?file=/src/App.vue

Steps to reproduce

import { createApp } from "vue";

const App = {
    directives: {
        mydir: {
            mounted(el, binding, vnode, oldVnode) {
                console.log(vnode.component) //vnode.component should be CompB vue instance, but now is null
            }
        }
    },

    render() {
        return (<div>
            <CompB name='a1' v-mydir="1" />
        </div>)
    }
}

let CompB = {
    props: ['name'],
    render() {
        return (<div>{'test: '   this.name}</div>);
    }
}

createApp(App).mount('#app');

What is expected?

vnode.component should be the CompB vue instance

What is actually happening?

vnode.component is null

@LinusBorg
Copy link
Member

the vnode represents the element, not the component.

The corrent way to access the component ìn Vue 3 is binding.instance

@zq8024
Copy link
Author
zq8024 commented Nov 6, 2020

the vnode represents the element, not the component.

The corrent way to access the component ìn Vue 3 is binding.instance

I want get CompB component instance in directive, but binding.instance is App component instance, how can i get CompB instance in directive?

@edison1105
Copy link
Member

try getCurrentInstance

@zq8024
Copy link
Author
zq8024 commented Nov 6, 2020

try getCurrentInstance

getCurrentInstance is return null, not CompB instance

@LinusBorg LinusBorg reopened this Nov 6, 2020
@LinusBorg
Copy link
Member

I'll reopen this for now to explore this. This is a bit of an edge case where in Vue 2, vnode.context would have given you ComponentB indeed, as the vnode context gives you the instance that the elements belongs to.

binding.instance gives you the instance whose template contains the directive, and I'd think that for many typical custom directive situations, that the more desirable behavior.

The two are usually the same except when using a directive on a child component.

I wouldn't not consider this a bug as it is working as expected. We can either find a way to support the edge case or document this as a breaking change.

@zq8024
Copy link
Author
zq8024 commented Nov 6, 2020

I'll reopen this for now to explore this. This is a bit of an edge case where in Vue 2, vnode.context would have given you ComponentB indeed, as the vnode context gives you the instance that the elements belongs to.

binding.instance gives you the instance whose template contains the directive, and I'd think that for many typical custom directive situations, that the more desirable behavior.

The two are usually the same except when using a directive on a child component.

I wouldn't not consider this a bug as it is working as expected. We can either find a way to support the edge case or document this as a breaking change.

I think use binding.context is more suitable for this,because the current vnode is the actual dom element point to, not the ComponentB's vnode

8000

@LinusBorg LinusBorg changed the title directive hooks argument vnode.component should not be null customd directives on components: Can't access child component in directive hooks. Nov 6, 2020
@LinusBorg LinusBorg changed the title customd directives on components: Can't access child component in directive hooks. custom directives on components: Can't access child component in directive hooks. Nov 7, 2020
@guogangj
Copy link

Is there any further news on this issue?

@cuiyajie
Copy link

I found binding.instance work normal in development, but it turned out to be VNode in production. I use vite for building.

@xsdream
Copy link
xsdream commented Jul 1, 2022

I found binding.instance work normal in development, but it turned out to be VNode in production. I use vite for building.

Finally solved? please

@matrunchyk
Copy link

I'm looking for this to resolve as well.

The two are usually the same except when using a directive on a child component.

That's exactly exception I ran into.

@tklkalok
Copy link

I am now facing the exact same situation that needs to access the child component's context (or called instance) in custom directives.

I found that for the mounted arguments ($el, $binding, $vnode, $prevVnode), $vnode.dirs[0].instance sometimes return the child component's context (or instance) and I can manipulate it but not always....

Back to the question itself, I am pretty sure that the child component's context (or instance) is needed to be included in custom directives in some of the use cases and that would be great if the Vue development team could consider adding it back in Vue 3. I'm still looking forward to a solution/workaround.

Cheers!

Vue Version: 3.2.33

@decademoon
Copy link

binding.instance gives you the instance whose template contains the directive, and I'd think that for many typical custom directive situations, that the more desirable behavior.

Really? What situations would you need the template component instance as opposed to the component instance the directive is applied to?

This is my use case:

const Autoselect = {
  mounted(el, binding, vnode) {
    // If the directive is applied to a component and that component has
    // an exposed select method, call that, otherwise call select on the DOM element
    if (typeof vnode.componentInstance?.select === 'function') {
      vnode.componentInstance.select();
    } else {
      el.select();
    }
  },
};

Some components have special logic for selecting its text contents. Is there no way to do this?

@decademoon
Copy link

I figured out I can do vnode.ctx.exposed.select() but that's delving into private APIs which isn't ideal.

@eric-gitta-moore
Copy link
eric-gitta-moore commented May 14, 2025

I figured out I can do vnode.ctx.exposed.select() but that's delving into private APIs which isn't ideal.

I'm also exploring similar things, but unfortunately, vnode.component cannot directly obtain the instance of the bound component. Instead, you can get vnode.ctx.proxy.

vnode.ctx.exposed.select() vs vnode.ctx.exposeProxy.select()

For me, I need to call the component to define functions through defineExpose, but I found there are two things named "expose" or something similar. What's the difference between these two?

@arcs-
Copy link
arcs- commented May 14, 2025

I figured out I can do vnode.ctx.exposed.select() but that's delving into private APIs which isn't ideal.

I'm also exploring similar things, but unfortunately, vnode.component cannot directly obtain the instance of the bound component. Instead, you can get vnode.ctx.proxy.

vnode.ctx.exposed.select() vs vnode.ctx.exposeProxy.select()

For me, I need to call the component to define functions through defineExpose, but I found there are two things named "expose" or something similar. What's the difference between these two?

I have a similar issue, however, while this works in a dev environment we don't get the exposed functions in a build

@eric-gitta-moore
Copy link

I figured out I can do vnode.ctx.exposed.select() but that's delving into private APIs which isn't ideal.

I'm also exploring similar things, but unfortunately, vnode.component cannot directly obtain the instance of the bound component. Instead, you can get vnode.ctx.proxy.
vnode.ctx.exposed.select() vs vnode.ctx.exposeProxy.select()
For me, I need to call the component to define functions through defineExpose, but I found there are two things named "expose" or something similar. What's the difference between these two?

I have a similar issue, however, while this works in a dev environment we don't get the exposed functions in a build

I'm sorry that I gave up using custom directives. I believe this is not the functionality I need. The desired feature should be more similar to HOC in React. I just hope that whenever data is passed to the child component, I have the ability to intercept and modify it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

0