7

I've got an error when tried to declare a variable in the usual way like this:

   Vue.directive('my-directive', {
        varA: '', 
        inserted: function(el, binding, vnode){
              this.varA = 'test'; // TypeError: Cannot set property 
                                  // 'varA ' of undefined
        },
    });

TypeError: Cannot set property 'varA ' of undefined

How do you declare variables in Vue directives?

3 Answers 3

9

In Vue directives, when you need to store a value it is generally stored on the element.

Vue.directive('my-directive', {
  inserted: function(el, binding, vnode){
    el.varA = 'test'; 
  },
});

The element is passed in as an argument to each of the lifecycle events in a directive and you can access the value later from el.varA.

Sign up to request clarification or add additional context in comments.

2 Comments

Is it bad decision to save state inside directive? Can you tell about your opinion / attitude about this. Should we create a vue component instead? Or that's depends on programmer preferences, only. (see @user1585345 comment).
@EvgeniyMiroshnichenko I don't use directives very often at all. I find in almost all cases I can make a component that does what I need. I don't think it's necessarily a bad thing to store state in a directive, I just don't find the need often.
4

There seems to be 2 ways for this:

  1. According to this comment on github, you may define a stateful directive like this:

    Vue.directive('my-directive', (() => {
        let varA = '';
        return {
            inserted: function(el, binding, vnode){
                varA = 'test'; 
            },
        };
    })());
    
  2. According to a note box on Vue.js docs:

    If you need to share information across hooks, it is recommended to do so through element’s dataset.

    Vue.directive('my-directive', {
        inserted: function(el, binding, vnode){
            el.dataset.varA = 'test'; 
        },
    });
    

2 Comments

the first approach is not a "stateful" directive per definition. varA is a variable that has the same state for every directive of the kind my-directive. If you need a state save it to the element.
The first approach’s point was to use a WeakMap to index state per bound element. There is a single WeakMap for all instances of the directive, but each directive can only access its own element’s state through the WeakMap. Since it’s not a regular Map, it also avoids memory leaks due to the key not being counted as a reference by the garbage collector.
1

Your this is not what you think it is. If you do console.log(this) inside your function, you'll see that this is the window.

Looking at the doc, directives are for '...cases where you just need some low-level DOM access on plain elements'. So there's no provision for directives to have state. I suspect you need a component, not a directive. What are you trying to do? You can go a long way in vue without ever needing to write a directive.

2 Comments

I was going to store some HTML element initial states inside directive, before they will be changed by directive. I wanted to have opportunity to set those initial states back when I need that. That was the main reason why I was going to use directive state.
That sounds a little louche to me! You should be trying to keep all your state in a viewmodel, and trying to avoid event handlers. The markup should be dumb, stateless, and reactive. Why not add an initialState property to your viewModel, then, when you need to, state = initialState, and the changes flow onto your page.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.