vuejs / vue

This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
http://v2.vuejs.org
MIT License
208.01k stars 33.69k forks source link

Formatters and Parsers #1141

Closed JosephSilber closed 9 years ago

JosephSilber commented 9 years ago

Is there any way to accomplish in Vue what Formatters and Parsers do in Angular?

If not, would that be a reasonable request?


For a single value you could maybe use a computed property, but that's a single non-reusable transformation. If you want to run the value through a pipeline, well... you can't.

Also, if your value is in a v-repeat, you can't use a computed property anymore; you'll have to create a component for your repeater...

None of that is ideal.


Here's my current use-case: I'm trying to convert this simple online invoice creator from jQuery-spaghetti to Vue. As you can see, the values in the input elements are/should all be formatted as currency, but the underlying model value has to be a number so that you can run your math on them.

yyx990803 commented 9 years ago

It was briefly mentioned in the guide but I think two-way filters are what you're looking for: http://vuejs.org/guide/custom-filter.html#Two-way_Filters

JosephSilber commented 9 years ago

They're not exactly the same thing: http://jsfiddle.net/6jjuoypf/

The two-way filters don't allow you to type anything you want into the input. Unless you use lazy, which is not what I want in this context.

Play with that fiddle. It's messed up on so many fronts:

  1. If you empty the input, you can't enter anything anymore. You're stuck on $0.00, since it keeps on formatting it.
  2. As is, the value starts out as $294.32. Hitting backspace once will change it to $294.30. From there you can press backspace as many times as you want, but nothing will change.

Maybe all this can be fixed by only triggering the "read" lazily?

yyx990803 commented 9 years ago

Well, they are the same thing, it's just formatting user input is itself a very tricky thing. I don't think you'd get what you expect with Angular formatters/parsers either.

Think about what you are trying to do: it's impossible to have a 1:1 transform relationship between the user input value and the underlying model value: both $123. and $123.00 gets converted to the same number, there's no way to know what text we should format 123 back into.

So yeah, what we actually want is "persist as the user types, but format only when the user blurs". Two-way filters are not created for this use case. Or, more generally, two-way binding just doesn't make sense in this case. You have to have two separate piece of state to store the underlying value and the display value, and handle input and blur events separately: http://jsfiddle.net/yyx990803/6jjuoypf/1/

Closing because formatters/parsers won't solve this issue.

JosephSilber commented 9 years ago

@yyx990803 formatters in angular are only invoked if the model changes through a source other than the form element. This prevents all the issues outlined above.

See this example: http://jsfiddle.net/3yn8hoyp/

If you type 3.5 into the input field, it'll stay that way. But if you set the value through the button, the input field will be set to $3.50.

Now, they don't call the formatter on blur - which I think they should - but that's a different point. The most important thing is that the formatters are not called as you type!

yyx990803 commented 9 years ago

@JosephSilber ah, that makes sense. This would make two-way filters easier to use.

JosephSilber commented 9 years ago

@yyx990803 I'm not sure I understand you. Are you saying you think it'll be a good idea to have this be the default behavior for two-way filters? And if so, what do you think of calling the "read" on blur?

yyx990803 commented 9 years ago

@JosephSilber yes, the current two-way filter behavior is confusing and hard to use. I think the angular formatter behavior simplifies the issue. We just need to prevent triggering model->view updates when the user is typing.

JosephSilber commented 9 years ago

Can you please re-open this issue then?

JosephSilber commented 9 years ago

Beautiful! Thank you so very much!

http://jsfiddle.net/6jjuoypf/2/

yyx990803 commented 9 years ago

:sunglasses:

jimping commented 8 years ago

How to do that in vuejs 2.0? The possibility to use an object as filter with read and write functions does not work anymore

LinusBorg commented 8 years ago

https://vuejs.org/guide/migration.html#Two-Way-Filters-deprecated

murilolivorato commented 7 years ago

to me it didnt work , when I try to use filter inside the input it gives an error . It dont aloud me to use a filter like this v-model="price | currency" like in this example - https://vuejs.org/v2/guide/migration.html#Two-Way-Filters-replaced

I am using vue - 2.1.8 , does some one knows whats is wrong ?