6

I'm trying to work out how I can make a custom Vue conditional directive. I know I could just write a global method and call it inside a v-if, but for code clarity I'd like to have a custom directive.

The aim is to decorate an element with the directive and pass a Guid to it (it's all for handling conditional rednering depending on user permissions): v-permission="'4ECE1FD4-4019-4CA2-AB9E-0A555CCBDB5B'"

At the moment, I just add display: none to the element in the directive's bind method and this is fine for hiding the content but it would be better performance wise if the element was never rendered.

Any ideas how I can achieve this?

Current directive code is as follows:

import Vue from 'vue'

Vue.directive('permission', {
  bind: function (el, binding, vnode) {
    if (binding.value) {
      let hasPermission = 
vnode.context.$store.getters.hasApiPermission(binding.value)
      if (!hasPermission) {
        el.style.display = 'none'
      }
    } else {
      console.error('You must specify a permission ID')
    }
  }
})
2
  • I would recommend not making permission decisions on the client. It's too insecure of an environment. Makes it easier for hackers to glean information about your site (as well as exposing GUIDs that control permissions). Commented Nov 27, 2017 at 14:12
  • 2
    @PatrickSteele no decision is made on the client, this is just to hide unnecessary parts of the UI. All permissions use Guids and API calls are made using signed JWT so even if somebody did reverse engineer all the Guids used, there's nothing that could be done with that information Commented Nov 27, 2017 at 22:00

2 Answers 2

8

Well it is possible using inserted hook:

inserted: called when the bound element has been inserted into its parent node.

example code snip:

Vue.directive('permission', {
  inserted: function (el, binding, vnode) {
    if (binding.value) {
      let hasPermission = 
vnode.context.$store.getters.hasApiPermission(binding.value)
      if (!hasPermission) {
        el.parentNode.removeChild(el)
      }
    } else {
      console.error('You must specify a permission ID')
    }
  }
})

However, it is still much more better to use the built-in v-if directive. Since Vue 2 is base on virtual DOM it will never render if the statement returns false. In this custom directive case it will be rendered firstly and removed afterwards.

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

Comments

1

I'm not sure if it is possible to achieve what you want. But I'm also not sure if it is really necessary. I think that construction like this, ...

<tag v-if="getPerm('4ECE1FD4-4019-4CA2-AB9E-0A555CCBDB5B')">
  ...
</tag>

... is really declarative enough.

1 Comment

I also prefer this approach because it allows to use permissions logic in different contexts and combine it with other logic very easily: for example, you need to show an element in case if user is navigating to the tab and has permission to do this. I guess it's not possible to use 2 structural directives on the same element

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.