RobinHerbots / Inputmask

Input Mask plugin
https://robinherbots.github.io/Inputmask/
MIT License
6.39k stars 2.17k forks source link

How to remove delimiters from "value"? #2367

Open marbuser opened 4 years ago

marbuser commented 4 years ago

I'm trying to make a currency input where displayed to the user is the value with delimiters etc... but the actual value of the input is stored in cents with no delimiter.

E.g 14.99 on display will become 1499 as a raw value on submit. My current config below returns 14.99.

new InputMask({
            alias: 'currency',
            numericInput: true,
}).mask(el);

Any ideas on if this is possible or not?

RobinHerbots commented 4 years ago

@marbuser ,

You can change the behavior with the onUnMask: function (maskedValue, unmaskedValue, opts) { } option

marbuser commented 4 years ago

@RobinHerbots The provided function doesn't get triggered? At no point does my message 'test' get outputted no matter how much I interact with the input.

new InputMask({
            alias: 'currency',
            numericInput: true,
            onUnMask: function (maskedValue, unmaskedValue, opts) {
                console.log('test')
            }
        }).mask($refs.input);
RobinHerbots commented 4 years ago

@marbuser ,

Also include the removeMaskOnSubmit: true option

marbuser commented 4 years ago

@RobinHerbots

I'm using a technology called Livewire which uses HTML Dom Diffing on changes to sync with server variables instead of on "submit".

Is there anyway I can just have it return an unmasked value without all this extra stuff like a simple function call or something? It feels like a lot of different configuration options I need to set and a lot of hoop jumping for something that I was under the assumption was a very common thing and was an industry standard? E.g storing currency as cents. Or have I been misled in some way and this isn't the correct way to handle this?

I can manually trigger it by using the code above and manually setting my own event listener with code something like this;

// `im` = InputMask instance.
im.el.addEventListener('input', event => {
    return im.unmaskedvalue(event.target.value);
});

However there is an issue with this in itself that if I put in 14,99 it should return 1499, yet it returns 149900 and I can't seem to find any sort of trailing zeros option in the documentation.

RobinHerbots commented 4 years ago

@marbuser ,

In the default scenario 14,99 should return 1499.00 and 14.99 returns 14.99 , is the groupsseparator.

RobinHerbots commented 4 years ago

@marbuser,

You can use the autoUnmask option in your case I think

marbuser commented 4 years ago

@RobinHerbots

Sorry but this is absurdely confusing. As I said previously I was under the assumption basically everyone stored currency as cents/lowest denominator. However, InputMask is treating currencies like we should be storing them as decimal values. So I'm a bit confused as to how exactly I can configure InputMask to do what I need it to do.

My initial value from my database is 1499 which should be converted to 14.99. However, InputMask with the currency default converts 1499 to 1,499.00.

Then on emit it turns 1499 masked to 1,499.00 to 149900. My currency just turned from 15 euros into 1500 euros. Definitely not the type of thing you want happening when dealing with something as sensitive/vital as money/currency. To clarify I'm talking about the actual underlying data here, not what is being displayed in the mask!!!

Sorry but this is just too confusing, and it seems to me like data is not even being treated as immutable and is just freely changing based on how the package wants to deal with it, and I'm not really comfortable with that given how sensitive money values are.

Can you please explain to me how I would achieve the functionality I want? Because I've played with every single config option I can find, with no luck, but I'm almost certain this must be something I'm doing wrong give how popular this package is.

marbuser commented 4 years ago

Here is an example of what I mean. I type in 1499 on the input and it masks to 14,99.

When the input loses focus my event listener is triggered. The variable unmaskedValue from onUnMask is correct and displays 1499. However, as soon as you use im.unmaskedvalue it adds these zeroes on the end and when you refocus the input it instantly updates as you can see in the GIF attached below.

CleanShot 2020-08-07 at 14 54 54

It would be very helpful if you could add a method (unless there already is one) globally that will return a "raw" value no matter the mask.

E.g

Also when setting the inputs initial value from the DB such as 1499 it automatically converts it to 149900 and shows the cast as 1,499.00 which is incorrect and I can find zero documentation about any of this so I'm a bit confused as to how exactly I'm supposed to use this package for this use-case.

RobinHerbots commented 4 years ago

@marbuser,

The trouble is with the assumption. The implementation in inputmask doesn't do any assumption on values.

Anyway, ....

You can create your own definition based on the current currency implementation. Call it customCurrency. And use that. Inputmask("customCurrency"), ...........


Inputmask.extendAliases({
            "customCurrency": {
                alias: "currency",
                autoUnmask: true,
                onUnMask: function (maskedValue, unmaskedValue, opts) {
                    return unmaskedValue;
                },
                onBeforeMask: function (initialValue, opts) {
                    var numberValue = initialValue.toString().split("");
                    numberValue.splice(numberValue.length - 2, 0, opts.radixPoint);
                    return numberValue.join("");
                }
            }
        });

        Inputmask("customCurrency").mask("test1");
``
basepack commented 3 years ago

@marbuser did you found a solution for autoUnmasking with Livewire?