vuejs/vue

Make directives available to all components within a render tree

trainiac opened this issue · 3 comments

What problem does this feature solve?

If you have a directive that relies on a piece of user data (e.g. language), in server side rendering you need to be able to create a new directive per request.

const getTranslateDirective = lang => ( {
  bind () {
    // access to lang
  },
  update () {
    // access to lang
  }
})

const translate = getTranslateDirective(() => parsedLangHeader.language)

// PROBLEM - this sets translate a directive globally across reqeusts
Vue.directive('translate', translate)

However this is a problem because when you call Vue.directive('translate', translate) this changes the translate directive across ALL requests.

What does the proposed API look like?

What is needed is a way to make directives available to a component and all of it's children components

const getTranslateDirective = lang => ( {
  bind () {
    // access to lang
  },
  update () {
    // access to lang
  }
})

const translate = getTranslateDirective(() => parsedLangHeader.language)

new Vue({
  directives: {
    translate: {
      module: translate,
      provide: true // Makes the directive available to this component and all of it's children.
    }
  }
})

FYI directives on the server needs to be implemented in a completely different fashion (as VNode transforms) because there's no DOM access: https://ssr.vuejs.org/en/api.html#directives

Also, I don't see the point of creating fresh directive instances for each request. You should somehow inject parsedLangHeader.language into your app as a piece of application state so it can be accessed across the app instance for that request.

@yyx990803 Thanks for taking the time to review this. When you say

You should somehow inject parsedLangHeader.language into your app as a piece of application state so it can be accessed across the app instance for that request.

I think for most cases that is appropriate but consider this example.

The desired translation directive is

<!-- The language is implicit -->
<div v-translate>Hello</div>

I could do this instead

<div v-translate='$store.state.language'>Hello</div>

But this feels very verbose to have to do all over the application.

Given Vue's exsiting API I dont see how you can avoid this.

I understand directives don't have DOM access on the server, but my feature request (most likely naive) is to make it easy to provide the application state to a directive at creating time per request so it doesnt have to be passed into the directive throughout the entire application

It looks like this might be solved with vuejs/rfcs#29