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?

Bert
  • 80,741
  • 17
  • 199
  • 164
Evgeniy Miroshnichenko
  • 1,788
  • 2
  • 19
  • 30

3 Answers3

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.

Bert
  • 80,741
  • 17
  • 199
  • 164
  • 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). – Evgeniy Miroshnichenko Jul 13 '17 at 07:56
  • @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. – Bert Jul 13 '17 at 16:04
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'; 
        },
    });
    
tony19
  • 125,647
  • 18
  • 229
  • 307
Hafez Divandari
  • 8,381
  • 4
  • 46
  • 63
  • 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. – Peter Hauer Mar 17 '23 at 15:14
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.

tony19
  • 125,647
  • 18
  • 229
  • 307
bbsimonbb
  • 27,056
  • 15
  • 80
  • 110
  • 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. – Evgeniy Miroshnichenko Jul 12 '17 at 08:04
  • 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. – bbsimonbb Jul 12 '17 at 08:46