muuucho's avatar
Level 11

Livewire - manipulate data before validation

I am learning Livewire 3. After submitting a form, I like to manipulate data before validation. I like to do this before validation:

$price = str_replace(',', '.', $price);

How can I make thise work?

0 likes
7 replies
LaryAI's avatar
Level 58

To manipulate data before validation in Livewire, you can use the updating or updated lifecycle hooks. These hooks allow you to intercept and modify data before it gets validated. Here's how you can achieve this:

  1. Use the updating hook to manipulate the data before it gets validated.
  2. Perform your string replacement within this hook.

Here's an example of how you can do this:

use Livewire\Component;

class YourComponent extends Component
{
    public $price;

    // This hook is called before the property is updated
    public function updatingPrice($value)
    {
        $this->price = str_replace(',', '.', $value);
    }

    public function submit()
    {
        $this->validate([
            'price' => 'required|numeric',
        ]);

        // Your form submission logic here
    }

    public function render()
    {
        return view('livewire.your-component');
    }
}

In this example:

  • The updatingPrice method is a lifecycle hook that is called before the price property is updated.
  • Inside this method, we replace commas with dots in the price value.
  • The submit method is where you perform the validation and handle the form submission.

This way, the price value is manipulated before it gets validated. You can adapt this approach to other properties and manipulations as needed.

muuucho's avatar
Level 11

Larrys suggestion, adding this method:

  public function updatingPrice($value)
    {
        $this->price = str_replace(',', '.', $value);
    }

Doesn't work. I am still getting the error

SQLSTATE[01000]: Warning: 1265 Data truncated for column 'price' at row 1
jlrdw's avatar

I would suggest validate first.

JussiMannisto's avatar

If you use a form request, you can modify the data before validation. But you'd first have to check that the value is present and a scalar. So you're validating, mutating, then validating again...

I'd rather accept a single format and have the front end handle formatting.

muuucho's avatar
Level 11

@JussiMannisto It doesn't seem to be compatible with Livewire. Error says:

Declaration of App\Livewire\Pubs\Form::prepareForValidation() must be compatible with Livewire\Component::prepareForValidation($attributes)

I also tried updated(), updating(), updatingPrice(), updatedPrice. It just doesn't work.

I use Laravel 10 + Livewire 3

muuucho's avatar
muuucho
OP
Best Answer
Level 11

I solved it like this for now (btw, the column name is cash):

public function rules(): array
    {
        return [
            'name' => ['required', 'string'],
            'type_id' => ['required', 'integer', 'exists:types,id'],
            'tags' => ['required', 'array'],
            'vat' => ['bool'],
            'gender' => ['required', Rule::in(['male', 'female'])],
            'cash' => ['required', 'numeric', 'integer'],
        ];
    }

    protected $messages = [
        'cash.integer' => 'The Cash must be a valid number.',
    ];
    public function updatedCash()
    {
        $c = str_replace(',', '.', $this->cash);
        if(is_numeric($c)){
            $this->cash = round($c * 100, 0); // save as int
        }
    }

Downside: Let's say I have 100.5 stored in a post. I like to display it as 100,5 when the user edits the post so that it is as the user expects (European user, that is). However, if the field is not updated when posted, the updatedCash() will not run, so the coma separated float will fail in the validation process. Because of that, I have to display a float in the edit form using the dot separator instead. Not a big deal maybe, yet not perfect. A better solution is welcome.

sllkevin's avatar

I discovered this topic after having a similar issue. However, updatingProperty($value) does not seem to work with my scenario where I'm using #[Validate] attribute on the property for a domain URL in a simple Volt component.

In my case, I wrote a function to ensure "https://" is prefixed to a string before validating, otherwise the validation will fail immediate, on blur. I wanted to format that string before validation.

My solution is to call the filter function in the rules() method just before returning the rules array. See summary of my solution below:

#[Validate]
public ?string $domain;

protected function rules()
{
	$this->domain = isset($this->domain) 
		? Application::formatDomainString($this->domain) : null;

	return [
		'domain' => 
'nullable:string|url:http,https|unique:applications,domain,'.$this->application->id,
	];
}
<flux:input wire:model.blur="domain" />

Please or to participate in this conversation.