Manipulating dom of target from vue directive

Viewed 417

I want to define a vue directive that toggles display of a popup on click, what I have now is:

toggle.js

export default {
    bind(el, binding) {
        console.log(binding.value); // this is undefined

        el.onclick = function() {
            console.log(binding.value); // this is undefined as well

            // toggle menu element display
        };
    }
};

component.vue

<template>
    <button v-toggle="$refs.menu">
        ...
    </button>
    <div ref="menu">
        ...
    </div>
</template>

<script>
    import Toggle from 'path/to/toggle.js';

    export default {
        name: "Component",
        directives: {
            Toggle
        }
</script>

Inside bind function binding.value is always undefined, probably because menu reference isn't ready yet. What's the proper way of doing this?

1 Answers

$refs will not be populated at the time the directive is set up. You can make its expression a function, which will evaluate $refs.menu at the time the click happens, rather than at directive setup.

new Vue({
  el: '#app',
  directives: {
    toggle: {
      bind(el, binding) {
        el.onclick = function() {
          const target = binding.value();

          target.classList.toggle('closed');
        };
      }
    }
  }
});
.closed {
  display: none;
}
<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
  <button v-toggle="() => $refs.menu">
    Button
  </button>
  <div ref="menu">
    Some junk in the menu
  </div>
</div>

Related