wearebraid / vue-formulate

⚡️ The easiest way to build forms with Vue.
https://vueformulate.com
MIT License
2.25k stars 245 forks source link

Add a hook mechanism for manipulating the input model (Original: Ability to mask input values). #67

Open paulogr opened 4 years ago

paulogr commented 4 years ago

Describe the new feature you'd like

Many times we have to mask input values for better UX.

VueFormulate already have really good features and be able to mask a value is the only missing feature that makes me add an extra dependency to handle my forms.

Today I use vue-the-mask (https://github.com/vuejs-tips/vue-the-mask) but it seen dead, doesn't have any activity from the maintainer and a lot of good contributors PR to get merged.

What percentage of vue-formulate users would benefit?

80%

Let's talk about it.

justin-schroeder commented 4 years ago

I've wondered about adding support for something like this too. I think my approach to this would be to add this kind of support via a VueFormulate plugin. I like the syntax that vue-the-mask was using with a simple prop. It would take a very slight shift to the internal model to make it work, but nothing dramatic.

Ideally it could use something like https://nosir.github.io/cleave.js/ under the hood.

justin-schroeder commented 4 years ago

Putting this on the roadmap for 2.x.x. The only implementation in formulate itself will be a "mask" prop and config option that takes a function and will be used as in the model setter, but we'll leave it up to external libraries like cleave to do the actual masking.

frankdors commented 4 years ago

Support for Money https://github.com/vuejs-tips/v-money https://github.com/autoNumeric/autoNumeric https://github.com/probil/v-mask

hmaesta commented 4 years ago

Upvote for this 👍

vue-the-mask and v-money are both by @neves, so it may share some standardisations that can allow an easier integration with vue-formulate – but both projects haven't received commits for years and have a lot of pending pull requests 😢

text-mask is very popular, but also not maintained anymore. They recommend imaskjs, which appears to be a nice option and has an official Vue implementation.

I didn't know about cleave.js – as suggested by @justin-schroeder, but it has a lot of favs and a Vue example. Did you guys already worked with this?

gahabeen commented 4 years ago

Hey, I've implemented a solution to have masks with https://imask.js.org/ with FormulateForm or FormulateInput.

You can check working demos here: https://codesandbox.io/s/vue-formulate-extended-masks-9i1wy?file=/src/App.vue. Currently available from vue-formulate-extended (with peer depedencies, careful). Repo

I'd be happy to discuss how this could become a cleaner solution @justin-schroeder ;)

atharva3010 commented 4 years ago

+1 for @gahabeen's solution

gahabeen commented 4 years ago

I like this idea of creating a modelHook (similar to the nodeHook and componentHook we discussed and I implemented in `vue-formulate-extended).

We could build tiny plugins based on it like a vue-formulate-mask for ex or do you see these like features you'ld want to have in-house? @justin-schroeder

gahabeen commented 4 years ago

I've just made a PR (#166) to have a modelHook on FormulateInput (available through a schema with FormulateForm too).

It'll be super easy to have the mask feature once it's pushed! I made an example for a mask/format feature in a test there: https://github.com/wearebraid/vue-formulate/blob/b0dfc0d23c6caff9dd619b208522487ab126b58c/test/unit/FormulateForm.test.js#L828-L876

gahabeen commented 4 years ago

@paulogr @hmaesta @frankdors Text Mask is now part of the - now stabilized - plugin vue-formulate-extended.

Check it out in a live demo: https://codesandbox.io/s/text-mask-04dh5?file=/src/components/Sandbox.vue

justin-schroeder commented 4 years ago

I'm going to focus this thread around this idea @gahabeen and I have been kicking around of hooks as a first class citizen in Vue Formulate. Here's a proposed syntax:

Vue.use(VueFormulate, {
  hooks: {
    model: [], // used for masking, or mutating
    schema: [], // used for mutating an entire schema
    schemaNode: [] // used for mutating individual schema nodes
    // ... other things we think up
  }
})

Then on an individual input, we would also allow inline hooks:

<FormulateInput
  model-hook="myFn"
/>

Hooks would function using a middleware pattern, allowing for a stack of functions to work together. Also, to be clear, these hooks are not intended to be used by your average beginner. I think having easy to use plugins will be a must-have in order to expose a higher-level. A hook would look a lot like what @gahabeen has above (in the meantime, use his module!). Here's a simple one:

function numeric (model, next) {
  return isNaN(model) ? next(0) : next(parseInt(model, 10))
}

Still open to suggestions on this API.

chasegiunta commented 4 years ago

Not sure which hook this would apply to, but a use-case where this may be applicable is being able to set html form attributes globally. In our case, we're using standard html forms so every form needs method="post", but there are certain circumstances where things like enctype="multipart/form-data”, and `accept-charset="UTF-8" may be globally necessary as well. Perhaps hooks would help in this instance?

Also, since these are standard traditional forms, we're having to attach @submit="submit()" to every form instance. Would be great to use hooks to standardize this into every form instance hits this method without explicitly setting.

gahabeen commented 4 years ago

@justin-schroeder I like the more middleware-like implementation you suggested.

Also I'ld recommend something like function hook(value, context, next) where context contains specific data depending on the hook being used.

bbugh commented 4 years ago

This functionality would also be really useful for GraphQL. We're trying to replace a custom form setup with VueFormulate and we're running into #161. In our current code, we are using .number modifier to ensure our inputs are type cast at the form rather than all of the places we have to use them. If we could do something like cast all fields that are number validated, that would be helpful.

justin-schroeder commented 3 years ago

I'm still really in love with this feature, but now that we have a clear roadmap for 3.0 it feels like something that belongs inthat re-write rather than patched into 2.x feature set, re-tagged for 3.0

CavalcanteLeo commented 3 years ago

hey @gahabeen I sent a PR fixing the compatibility of the newer version of vue formulate..

Review it, please https://github.com/gahabeen/vue-formulate-extended/pull/18

adinvadim commented 3 years ago

Hi there! Any updates of this issue? Or we see this feature only in v3?

justin-schroeder commented 3 years ago

@adinvadim this will only be available in the next major release as it requires a underlying re-write to do well.

adinvadim commented 3 years ago

Okey, thank you! May be there is workaround or examples for add mask to common input?

justin-schroeder commented 3 years ago

You can checkout vue-formulate-extended. Looks like @CavalcanteLeo submitted a PR, but I think @gahabeen added some of these features to Vue Formulate using that plugin

adinvadim commented 3 years ago

Thank you! Im just looking vue-formulate-extended.

@gahabeen is there the plugin with this functionality? Or while everything in vue-formulate-extendete repository?

adamelevate commented 2 years ago

Has this been resolved yet? "vue-formulate-extended" doesn't seem to work upon install, and it looks like a dead/paused project. How can we add masks to these inputs?

Love the project btw.