filament: Money Mask fails the integer or numeric validation

Package

filament/forms

Package Version

v3.0.39

Laravel Version

v10.21.0

Livewire Version

v3.0.1

PHP Version

8.2.x

Problem description

When we use a money mask to add a thousand separators to an input field the validation fails and says it must be a numeric input.

Expected behavior

It must mask the value in the front end and return the unmasked value to the back end.

Steps to reproduce

create a text input like this:

                Forms\Components\TextInput::make('balance')
                    ->required()
                    ->integer()
                    ->mask(RawJs::make("\$money(\$input)"))
                    ->default(0),

then send a value like 1000000 and you encounter this error: The balance field must be a number. while the input is actually a number just masked to have a thousand separators.

Reproduction repository

https://github.com/ariaieboy/filament-mask-bug

Relevant log output

No response

About this issue

  • Original URL
  • State: closed
  • Created 10 months ago
  • Reactions: 1
  • Comments: 19 (15 by maintainers)

Most upvoted comments

->stripCharacters('.')
->mutateStateForValidationUsing(fn ($state) => str_replace(',', '.', $state))
->mutateDehydratedStateUsing(fn ($state) => str_replace(',', '.', $state))

@Akhmami Yes you have to not use numeric for validation, and then use a cast before saving to the database.

Removing the validation is not a good idea. Besides the security problems, we can not use other laravel validation rules either. for example, if I have 2 column, one of them must be bigger than the other one, and when I use that rule without the numeric validation, laravel compare them as 2 string instead of 2 integer.

I temporarily removed the mask from my project, but since I am working with big numbers in my application, I must have a thousand separators.

1 dollar is equal to 500,000 rial over here so numbers can get big very soon 😄

Fixed by #10092 when you use stripCharacters()

@sibdib I’ve created a small package called filament-currency that you can fix this problem using it.

@andrewdwallo No This method does not do anything in the back-end. All magic happens in the front end. It masks the input using alpinejs $money and returns the unmasked value to the backend.

    {
        input:\$wire.{$applyStateBindingModifiers("\$entangle('{$statePath}')")},
        masked:'',
        init(){
            this.masked = this.input;
            \$watch('masked',()=>this.updateInput());
        },
        updateInput(){
            this.input = this.masked.replaceAll('$thousandSeparator','').replaceAll('$decimalSeparator','.');
        }
    }

it might not be the best solution, but it solves my problem for now. you can customize the thousandSeparator, decimalSeparator, and the precision.

@Akhmami until this issue get fixed you can use my filament-currency package.

instead of mask just use currencyMask

@ariaieboy Hey man, I’m definitely not disagreeing with you… I was just providing the solution I was told to use.

Nothing we can do about this; the validation doesn’t allow characters like $, it’s a browser thing

That’s not a browser validation error. The problem is that the Alpine masks the 1000000 into 1,000,000, and the laravel validation does not accept 1,000,000 as an integer.

We need a way to remove the thousand separator when the value passes to the backend.

In V2, the mask option didn’t have this problem. Because the mask only applies in the front end, and the value that passes to the backend is the non-masked value.