vincent15000's avatar

Why does Livewire databinding return a Stringable for an input type number ?

Hello,

Something strange for me.

I have a form with the following example.

<input type="number" wire:model="form.quantity" />

You can notice that the quantity is a property of a Livewire form.

When I display the form quantity with dd(), I get an integer.

But when I try to validate that the form quantity is for example of a minimum value, the validation method receives a Stringable object instead of an integer and the validation cannot work.

In the documentation, it's written that when I need to evaluate if the typed value is greater or equal than 4, I need to use both integer and min lije this : integer|min:4, and it's exactly hat I'm doing.

So it's quite difficult to understand why I get a Stringable object only for the validation.

For the moment, to get the code work, I have had to create a custom rule and handle the Stringable object to extract the string and convert it to an integer.

Do you have any idea or suggestion for me ?

Thanks a lot.

V

0 likes
15 replies
s4muel's avatar

what exactly do you mean by validation method? if i get you correctly, you set the quantity as an attribute in your livewire Form dedicated object something like this

class QuantityForm extends Form
{
    public int $quantity = 0;
}

since your quantity attribute is integer when you dd() it, i suppose you define the type over here (and do not do any magic with request input in middleware or something)

"validation method" => from what i deduce, you do not use validate attributes (#[Validate]...), nor validation rules method (public function rules())...

how do you access it then? because there is no way in here ($this->quantity)or this form's parent component $this->form->quantity, that this attribute is Stringable đŸ€Ż.

show us the validation code

1 like
vincent15000's avatar

@s4muel

Sorry for some confusing informations.

I use the #[Validate()] attribute. And I validate manually with $validated = $this->validate().

In the form or in the form page, when I dd() the quantity property, I see an integer. But when I have created a custom rule, when I access the quantity, I notice that it's a Stringable object.

Old code is not working (I have already posted something here about this code)

#[Validate('required', message: 'La quantitĂ© doit ĂȘtre un nombre entier.', onUpdate: false)]
#[Validate('integer', message: 'La quantité est obligatoire.', onUpdate: false)]
#[Validate('min:1', message: 'La quantitĂ© doit ĂȘtre supĂ©rieur ou Ă©gal Ă  1.', onUpdate: false)]
#[Validate('max:20', message: 'La quantitĂ© doit ĂȘtre infĂ©rieur ou Ă©gal Ă  20.', onUpdate: false)]
public $quantity = null;

New code works great

#[Validate([
    'quantity' => [
        'required',
        'integer',
        new MinValue(1, 'La quantitĂ© doit ĂȘtre supĂ©rieur ou Ă©gal Ă  {value}.'),
        new MaxValue(255, 'La quantitĂ© doit ĂȘtre infĂ©rieur ou Ă©gal Ă  {value}.'),
    ]
], message: [
    'required' => 'La quantité est obligatoire.',
    'integer' => 'La quantitĂ© doit ĂȘtre un nombre entier.',
], onUpdate: false)]
public $quantity = null;
vincent15000's avatar

@s4muel And if I specify the int type, I get this error message.

Cannot assign Illuminate\Support\Stringable to property App\Livewire\Forms\RecipeForm::$quantity of type int

What is exactly the problem I noticed : Livewire seems to return a Stringable object for integers.

s4muel's avatar

@vincent15000 check your component. the only scenario i can simulate (with type specified public int $quantity) to get your error (Cannot assign Illuminate\Support\Stringable to property App\Livewire\Forms\RecipeForm::$quantity of type int) is when i do some property setting during mounting on the main (not form) component:

public function mount()
{
    $this->form->quantity = str('hello');
}
1 like
vincent15000's avatar

@s4muel Do you mean that you have tried this ?

#[Validate('required', message: 'La quantitĂ© doit ĂȘtre un nombre entier.', onUpdate: false)]
#[Validate('integer', message: 'La quantité est obligatoire.', onUpdate: false)]
#[Validate('min:1', message: 'La quantitĂ© doit ĂȘtre supĂ©rieur ou Ă©gal Ă  1.', onUpdate: false)]
#[Validate('max:20', message: 'La quantitĂ© doit ĂȘtre infĂ©rieur ou Ă©gal Ă  20.', onUpdate: false)]
public $quantity = null;

And it works ?

vincent15000's avatar

@s4muel I think I need time to find what's wrong in my code. For the moment I keep my custom rules with which it works.

Is it possible that the problem is due to the initialization of the properties in the form ?

public function set(Model $model)
{
	...
    $this->quantity = $model->quantity;
}
s4muel's avatar

@vincent15000 yep, gl đŸ€ž

could be. is the quantity on the model casted to a Stringable (via $casts or accessor/attribute cast). if coming from DB i would expect a simple string, but who knows.

does it work for you if you cast it here?

$this->quantity = (int) $model->quantity;
1 like
vincent15000's avatar

@s4muel I have just tried your suggestion, but it doesn't work better. And no the field is not cast.

1 like
s4muel's avatar

oh, pity. does it at least work for you if you skip the initialization (basically just as in my wirebox example)? so we can rule out version inconsistency. the wirebox is:

Livewire Version: v3.4.4
Laravel Version:  v10.42.0
PHP Version:      v8.1.12

i would go with xdebug and step up to get the point where it is set to stringable. if nothing else, just out of curiosity:)

2 likes
vincent15000's avatar

@s4muel No, even if I don't initialize the form, it doesn't work.

This will be, as you say, a step to step research of the source of the problem.

1 like
abduazam's avatar

Can't you check with a numeric validation?

#[Validate('numeric|min:4')]
public int $quantity;

I always use this approach.

1 like
vincent15000's avatar
vincent15000
OP
Best Answer
Level 63

Here is the solution, but you couldn't guess.

I have searched why the rules I presented in the post didn't work.

In fact they work fine, but only if I don't filter the fields. In the form, before validation, I apply a filter to remove all unnecessary spaces and return null if the string is null. The problem is that I filtered also the numeric values, but it wasn't a good idea.

Now I don't filter the numeric values any more and these filters work fine.

#[Validate('required', message: 'Le nombre de portions est obligatoire.', onUpdate: false)]
#[Validate('integer', message: 'Le nombre de portions doit ĂȘtre un nombre entier.', onUpdate: false)]
#[Validate('min:1', message: 'Le nombre de portions doit ĂȘtre supĂ©rieur ou Ă©gal Ă  1.', onUpdate: false)]
#[Validate('max:255', message: 'Le nombre de portions doit ĂȘtre infĂ©rieur ou Ă©gal Ă  255.', onUpdate: false)]
public $portions = null;
1 like

Please or to participate in this conversation.