Vue: `this` undefined in filters

Created on 29 Jun 2017  路  9Comments  路  Source: vuejs/vue

Version

2.3.4

Reproduction link

https://jsfiddle.net/xweeqtuw/1/

Steps to reproduce

open the fiddle

What is expected?

this to be the component

What is actually happening?

this is undefined in commonJS and window in jsfiddle.


Is this intentional, or should this be the component? I'd expect it to be the component.

Is this a good candidate for my first PR? 馃槃

Most helpful comment

I'm absolutely convinced that filters must have a way access the context. The question's what core team is going to do about it?

All 9 comments

This is intentional in 2.x. Filters should be pure functions and should not be dependent on this context. If you need this you should use a computed property or just a method e.g. $translate(foo)

You can take this as a parameter for your filter function.

Also, I think it's better to support this context that we can take advantage of pipe style.

For example, if we have fn1, fn2 and fn3, and the code like this {{ somevalue | fn1| fn2 | fn3 }} is clearer and simpler than {{ fn3(fn2(fn1(somevalue))) }}.

I think I encountered a case in which it would be nice to have a context in a filter. I'm creating an geometry鈥搗isualization app, the core module is a projection of a real coordinate space on the screen. And there are objects at this space represented as vue components. I though filters would do the trick:

<canvas-component>
  <cavas-object
    :x="x | toPixelX"
    :y="y | toPixelY"/>
</canvas-component>

Props x and y are given in real unit, like meter, so to compute a filtered value, I need values of viewport's dimensions and some previously generated scale value.

I understand that I can use methods, and I'm actually using 'em. But I'm wondering if there are some options in my case.

I believe that there are some use cases that we need to access this in filter, for example in a SSR project: When we are implementing a translate filter, we need to create different translate instances for every request for different languages, and we can only access different instance via this.$ssrContext on server, so we have a workaround that change filter to method, but some people prefer a translate filter.

And we can also implement it in a hacky way which overwrite Vue.prototype._f method: https://github.com/JounQin/vue-translator/blob/master/lib/index.ts#L123-L137

However, it is just something we can do, but not recommended to do, because .call(this) is slower than direct calling.

Filter related source codes:
https://github.com/vuejs/vue/blob/master/src/core/instance/render-helpers/index.js#L23
https://github.com/vuejs/vue/blob/master/src/core/instance/render-helpers/resolve-filter.js#L8
https://github.com/vuejs/vue/blob/master/src/core/util/options.js#L401

I'm absolutely convinced that filters must have a way access the context. The question's what core team is going to do about it?

Yes I agree, there should be an option to use vue context in the filter, similar to child components. E.g. to be able to access parent component. I don't see the reason why filters should be pure functions. The pipe syntax looks better and is more readable than method calling, e.g. in number formatting where I need to access locale set on parent component: {{price | currency}} vs. {{currency(price)}}

i also agree with component context in filters, if not, there is no point in providing per-component filters as opposed to global filters.

my point is, you should be able to access the component from a component filter, but not able to access component from a global filter

i also agree with component context in filters, if not, there is no point in providing per-component filters as opposed to global filters.

Actually there is. Different third-party components may use different filters with the same name. You need this isolation to prevent collisions.

I'm absolutely convinced that filters must have a way access the context. The question's what core team is going to do about it?

Sorry but my opinion has not changed: filters should not, and will not have access to context. If you need context, use a method.

Was this page helpful?
0 / 5 - 0 ratings