I have following simple code:
define a test-comp component; define a custom directive log-something
within that component's template, i use a custom directive v-log-something;
within the diretive's bind function, i want to log out the belonging element's parentElement;
Unfortunately, the null result is returned.
Note: It works if I put the v-log-something diretive in a normal html tag( Not within the component's template).
I am not sure whether or not this is a bug. I guess it is caused by some lifecycle issue: When diretive's bind function is called, the belonging component has not been inserted into dom.
When can we make sure everything is in dom and we can access parentElement node within the directive's bind function safely??
here is the fiddle:
http://jsbin.com/wajarad/edit?html,js,console,output
<body id="body">
<test-comp></test-comp>
</body>
Vue.component('test-comp',{
template: '<div v-log-something>this comes from test-comp</div>'
});
Vue.directive('log-something',function(){
console.log(this.el.parentElement);
});
new Vue({
el: '#body'
});
You can do it in or after the ready hook.
You can use $nextTick at the moment to fix the issue. Let me come back at you when I have a better answer:
Vue.directive('log', function () {
this.vm.$nextTick(() => ...)
})
Components are compiled in a DocumentFragment before inserted, so you'll have to use one of the workarounds mentioned above.
BTW it also seems like a bad idea to access outside DOM from within a component.
@posva , thanks, got your workaround, it works now.
@Twiknight , Your workaround i can not catch up: How component ready function can access function defined in the directive bind function?
@yyx990803 , you are right, it is not a good idea to access outside dom from within a component, but in some situation, it is more reasonable to access parent within component itself. thanks for your great effort!
@cnweibo I mean, you can move your function from directive to a ready() function. Or you can use a ready mixin.
Another way is to define a event listener with your component, and emit the event after it's mounted (ready)
@Twiknight , thanks! got your 2nd point.. But for the first proposal of "move your function from directive to a read() function", I can not catch yet. The most annoying problem is: we can not make sure v-log-something directive attached element is in the dom.
What I raise this question is: I want the v-log-something directive can be used anywhere to access some information for its parent element.
thanks~!
@cnweibo sorry to have made a typo , I mean ready() hook.
you can declare a mixin:
const logMixin = {
ready: () => /*log something here*/
}
And then use it this way
const myOptions = {
/*your options*/,
mixins: [logMixin]
}
const myComp = Vue.component(myOptions)
see it here: http://vuejs.org/guide/mixins.html#Option-Merging
@Twiknight ,
Thanks, i got it.
Can someone elaborate on the best method on resolving this issue in Vue 2? I am running into a similar issue, however, I can't get access to the vue instance within the directive. "This'" scope is on the Window object instead of the Vue instance.
Is someone able to clarify on the best way to achieve waiting for the the target instance or component's ready state for the directive to use the appropriate "this" context to gain access to the Vue instance?
@nat1597 in Vue 2 directives changed a lot. Hook signatures are now different and no more this.
You can access the vm as vnode.context, with vnode being the third argument to the hook. And the old workaround with nextTick is still needed if you want to access vm from the directive's bind.
Thank you for your prompt reply this helps, I thought I tested a 3rd argument in bind() but I obviously missed it =).
So this is a sub issue of the ultimate goal I am aiming for and I've searched pretty extensively on how to do this but I'm pretty new to Vue so I don't have many of the directives/components concepts down.
Ultimately, I am trying to add a custom directive to a component I am building. The custom directive is a plugin I would like incorporated into the component's behavior and I am able to get it to work against basic html structure with a simple vue instance. However, my confusion arises with integrating this custom directive with the component's html template definition. I am having trouble with the directive accessing the vue instance I am attempting to bind to the directive.
I'm assuming I need to define this directive within 'props' in the component and define it within the ' I am able to instantiate it now with using vnode but I'm still not able to get it to work, I need a little more understanding on how a custom directive communicates with a component through props if that is indeed how the directive behavior is appropriately translated to components. Or if the 'directive' approach on incorporating other libraries into components is even the appropriate way anymore and there is a better approach I am unaware of that exists that's more suitable for this task. Thanks for the help.
I faced this issue in Vue 2.5.13.
Here is workaround works for me:
```js
bind(el, binding, vnode) {
vnode.context.$nextTick(() => {
// vnode.elm.parentElement
});
}
Most helpful comment
I faced this issue in Vue 2.5.13.
Here is workaround works for me:
```js
bind(el, binding, vnode) {
vnode.context.$nextTick(() => {
// vnode.elm.parentElement
});
}