Closed ecmel closed 8 years ago
@posva computed properties are not reusable.
Almost everything is reusable through a mixin. You can use a function that generates a mixin. This way you can bind a the computed property dynamically. I cannot put that example on a fiddle now but I would do it ASAP. However, I agree it's a very common use case for inputs to have transformations applied. A proper api or at least an explanation on the guide is necessary
On Tue, 13 Sep 2016, 18:48 Francisco Lourenço, notifications@github.com wrote:
@posva https://github.com/posva computed properties are not reusable.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/vuejs/vue/issues/3666#issuecomment-246746524, or mute the thread https://github.com/notifications/unsubscribe-auth/AAoicf33lCvETQc9LBQ5GGZ93ExPcLS_ks5qptPegaJpZM4J7vQ0 .
Almost everything is reusable through a mixin. You can use a function that generates a mixin. This way you can bind a the computed property dynamically. I cannot put that example on a fiddle now but I would do it ASAP. However, I agree it's a very common use case for inputs to have transformations applied. A proper api or at least an explanation on the guide is necessary
Put in another way, computed properties are not reusable. You can use factory functions + mixins as a work around, but the usability and readability doesn't compare.
For my project, I badly needed this feature so I used the recommended custom input approach:
InputCustom.js
define(function () {
return Vue.extend({
data: function () {
return {
focused: false
};
},
template: '<input @focus="onFocus" @blur="onBlur" @input="onInput" @change="setDisplayValue">',
props: ['value'],
watch: {
value: function () {
if (!this.focused) {
this.setDisplayValue();
}
}
},
mounted: function () {
this.setDisplayValue();
},
methods: {
onInput: function () {
this.$emit('input', this.parse(this.$el.value));
},
onFocus: function () {
this.focused = true;
},
onBlur: function () {
this.focused = false;
this.setDisplayValue();
},
setDisplayValue: function () {
this.$el.value = this.format(this.value);
}
}
});
});
InputText.js
define(['js/InputCustom'], function (InputCustom) {
return InputCustom.extend({
methods: {
parse: function (val) {
val = val.trim();
return val === '' ? null : val;
},
format: function (val) {
return val === null ? '' : val;
}
}
});
});
In my opinion, this approach is very convenient and I decided not to use any v-model modifiers at all including .lazy
.
For more customized use cases that built-in modifiers cannot support, what @ecmel mentioned is the recommended approach. We will document that in more details in the official guide.
The idea of this feature proposal is to take advantage of the existing v-model
directive, which already works with every input
element. To save the work of writing InputCustom.js in every project, because that has been done already in v-model
, having only to write the equivalent of InputText.js in a custom modifier, which contains all the logic which needs to be modified most of the times. The fact that v-model
already ships with modifiers proves that it is an intuitive and desirable pattern. It is only natural to facilitate the creation of custom modifiers, to save the work of creating custom elements and having to implement dom/model binding manually.
If it makes sense from the API perspective, would be interesting to know what are the technical limitations which are driving the decision of not implementing this feature.
Any chance we can get this issue reopened? A common use case for me is the need to automatically format data in a field as it's being typed in. Something like taking '101216' and turning it into '10/12/16'. Being able to create a custom v-model modifier would greatly simplify my code since I could write v-model.date instead of having to build a custom input component with props and events.
After using vue js for a while now in my project, I think this issue should indeed be reopened.
At least we need an undef
modifier.
I agree that this issue should be reopened. Not sure what undef
was supposed to do, but I would like a v-model
modifier that sets my variable to null
in case the input's trimmed value is an empty string.
I'd love to be able to do that myself in a straightforward way.
Functionality more redundant than this has been added for example with https://github.com/vuejs/vue/issues/5194 . From the outside, Vue appears to slowly be compromising some of its principles in favour of conventions and practices promoted by the react community. Slightly deviating from the qualities which made it stand out in the first place. Would be interesting to know if this is a conscious decision with the intention to make migration from react easier, or just coincidence.
Writing custom components is fine but if you want to use a 3rd party custom component like https://github.com/text-mask/text-mask/tree/master/vue#readme there is no straight forward way to sanitize the masked input to model values except using computed properties.
So, I just want to use an HTML standard input[type=date] field to edit a date type in my model and this wonderfully powerfull and extensible framework can't do that out of the box? Can't read the date into the field, overwrite my date with a string in my data after I select a date. This solution could be written in two lines with two-way filters or with modifier.
But the best solution at all would be to just support it natively as they do for checkbox and other standard input field, why is "date" a special thing?
+1 for custom modifiers. Seems like a no brainer, unless there is a good reason not to?
Masking input and parsing the value for application use is a very common practice, and making some "syntatic sugar" like v-model.lazy.currency="amount" would be amazing!
1+ for custom modifiers. I have a simple radio input with true|false values which evaluate to strings - But I need them as an boolean - computed properties will not be smart in this case since I need to reimplement a computed property for every radio input. E.g. Having 100 radio inputs will result in 100 computed properties
+1 for custom modifiers but I agree with tobei -- input[type=date] should work automagically.
+1 for custom modifiers.
I come from an Angular background, and just started with vue, and saw this thread.
I feel it would really help having something like Angular's parsers and formatters, in Vue too. If I could do something like v-model.dateFormat and result in something like mm/dd/yyyy, it would be really cool.
EDIT: looks like it reiterated on what @restored18 said. +1 to you too
+1 for custom v-model modifiers.
In my case I loop over a few nested objects retrieved in JSON, and use a single HTML template (rather than a template per object). In this case I believe computed properties don't work?
I'm currently putting in custom conversion methods between the server format and v-model format when fetching and sending data, but would love for something just "built-in" that I could pass the functions to.
+1 to this. It used to be available before 2.2. You could access the property through,
this.$vnode.data.directives
It was removed with the addition of custom model input values, but was a very useful feature and should be back in the framework.
+1 for this.
Custom v-model modifiers would be great!
+1 in 2018 as well ...
+1 It's a necessary feature for DRY code in my opinion. Right now I have to create 10 watchers that does the same thing for a form with a lot of input. A custom modifier would solve everything.
+1 I just started vue and already need these type of two way filters ...
+1 definitely needed
+1
You can build helpers like this for most use-cases IMO
@nickmessing that doesn't cover the (really useful) use case being described here, which is in-place modification of the input text. If you have an input box that you want to always be formatted like a phone, you'd have <input v-model.phone="some_data">
. When the user entered text, it would automatically format it.
This seems like such a basic feature and it's more difficult than it should be right now. The behavior already exists in the framework, but for some reason it's restricted to framework-only code. We want to be able to add a custom modifier that would do this, which is reusable across components and projects, just like filters and directives are right now.
@bbugh totally agree, i'm having a similar case with formatting IBANs and it would be such a nice and declerative way to simply put v-model.iban="payment.iban"
in there...
@franciscolourenco maybe someone could put some reasoning behind why this should not be supported by the framework so that it becomes more obvious.
+1 for custom modifiers, there are plenty of use-cases that could be accomplished with this feature
In our application there are few different inputs to format currencies, we always store cents amount in model, but display nicely formatted dollars amounts in inputs (so 123456 in model shown as $1,234.56) <input v-model.dollars="cents" />
Other use-case is sanitizing and unescaping html fields in order to prevent XSS atacks (Model stores "A & B
" while input shows "A & B
") <input v-model.html="text" />
+1
+1
+1 for custom modifiers.
I was really surprised that I can't do something like v-model.trim.uppercase=...
+1
+1
+1
+1
Native v-model
input modifiers would be a great feature. As people mention here, there are a lot of use cases. I had a need of date and currency modifiers for all projects I've been working on.
should we open an issue here? https://github.com/vuejs/rfcs
i have already +1 this, but want to throw a note for people who need something “now”
while modifier is way more effecient, i have been able to achieve the same effect using a transparent input/component with a computed getter/setter field.
i can share an example if someone needs it
We did not implement this because there are many things to be considered in this seemingly easy feature:
The built-in modifiers are in fact compile-time hints that generates different compiled code. Custom modifiers likely need to be defined using a runtime config, which is a different mechanism.
For runtime config, what kind of API should we expose for this?
We had two-way filters in the past. A two-way value transform requires the user to implement impeccable logic so that the two-way binding can stabilize. Otherwise you risk putting your entire app in an infinite loop for edge cases.
.number
and .trim
is because they are in-fact one-way transforms (only applied when syncing DOM value to component data) and thus guaranteed to stabilize.How should custom modifiers behave when v-model
is used on a component?
How should custom modifiers behave on non-text input types, e.g. radio
, checkbox
and most importantly, <select>
?
All of these questions are unanswered and makes the request more complex than it seems. This is why I agree it would be a good candidate for a proper RFC that covers all these if anyone really want this feature. Until then, more +1s doesn't move it forward in any way.
@rkingon There is already an example in https://github.com/vuejs/vue/issues/3666#issuecomment-249583603, but if yours is different/better, just post it. It can be useful for novices.
@Gotterbild i did miss that sample, but it is widely over complicated in later versions of Vue (that could have been pre transparent component support)
here is a very simple one I have that just converts a percent to decimal (ie: 4.5 -> .045) & vice versa ("view" value and "model" value)
<template>
<input type="number" v-on="listeners" v-model="innerValue">
</template>
<script>
export default {
props: ['value'],
computed: {
listeners () {
const { input, ...listeners } = this.$listeners
return listeners
},
innerValue: {
get () {
return (this.value) ? `${(this.value * 100)}` : ''
},
set (_val) {
const val = (_val) ? (_val / 100) : ''
this.$emit('input', val)
}
}
}
}
</script>
this is more simple than the above since you do not have to respecify all of the focus/blur/etc
@yyx990803 thanks for giving more background information on this topic.
for my use-cases, i do not "need" custom modifieres. it's just that from a consumers-perspective, it would make sense that vue has a way to build your own. it basically has that for everything, except modifieres 😄
while i could find ways to create something that properly encapsulates my transformation logic and that i could reuse, i think that having a proper API for such use-cases would open up a much broader way of sharing common code through a collection of "best-practice modifiers".
I came here because I was looking to make modifier to convert string to uppercase
I wanted to create it like v-model.uppercase="username"
I ended up using custom directive
Vue.directive('uppercase', {
update (el) {
el.value = el.value.toUpperCase()
},
})
<input type="text" v-model="username" v-uppercase>
Custom directives should be enough for an alternative. Or is there something that only possible with custom v-model modifier?
@Christhofernatalius considering v-model
is simply a directive, couldn't you eliminate the v-model
in favor of the custom directive? this way you're not updating twice?
@Christhofernatalius considering
v-model
is simply a directive, couldn't you eliminate thev-model
in favor of the custom directive? this way you're not updating twice?
@rkingon Is it updating twice? So, if I don't use v-model, then I need to also add bind and unbind hook for input listener, and update username value?
EDIT: Isn't using computed with setter and getter also updating twice? EDIT 2: I tried console log the watcher and directive, each only print once for every keystroke.
i haven't tried it, merely speculation -- i suppose the idea of two directives to update one value just feels a bit funny to me, but if you've checked it out, i don't see anything wrong with it.
my component workaround has limitations too, which is why i'm still in favor of a modifier -- ie: it requires an element, more rendering time, & only works as a component in how that component is defined (ie: an input field) vs being able to even simply use it on some arbitrary component/element which is the power of a directive.
two ways to skin the cat, nice to have options :)
Is there an RFC for this?
i don't think so
I could create it but does it just mean adding an issue in that RFC repo or something else?
https://github.com/vuejs/rfcs#what-the-process-is does this answer your question?
We have
.lazy
,.number
,.trim
and.undef
is on the way.Apart from
.lazy
they all work like two-way filters.Since 2.0 does not support 2 way filters, may be there should be a new api to add custom v-model modifiers to fulfill the same need.