protonemedia / laravel-form-components

A set of Blade components to rapidly build forms with Tailwind CSS (v1.0 and v2.0) and Bootstrap 4/5. Supports validation, model binding, default values, translations, Laravel Livewire, includes default vendor styling and fully customizable!
https://protone.media/blog/laravel-form-components-to-rapidly-build-forms-with-tailwind-css-and-bootstrap-4
MIT License
814 stars 104 forks source link

Radio inputs - Non-string values considered false are not bound (in edit view or after wrong validation) #64

Closed supergreentony closed 3 years ago

supergreentony commented 3 years ago

Hi,

I have boolean field create_role (0 or 1) from my database that I've bound to a radio input :

@bind($user)
        <x-form-group class="ms-3" label="Is this user able to create new articles?" inline>
            <x-form-radio name="create_article" value="0" label="no" default/>
            <x-form-radio name="create_article" value="1" label="yes"/>
        </x-form-group>
@endbind

But if I edit or update with a wrong validation another field, value 0 (false is the same) is not bound. Its because of the comparison in the ProtoneMedia\LaravelFormComponents\Components\FormRadio.php file at line 31 and line 38

Is there any simple way you use to fix that problem? I've already fixed it by my own but not sure its the better one...

I have modified the same file as before like this :

<?php

namespace ProtoneMedia\LaravelFormComponents\Components;

class FormRadio extends Component
{
    use HandlesValidationErrors;
    use HandlesBoundValues;

    public string $name;
    public string $label;
    public $value;
    public bool $checked = false;

    public function __construct(
        string $name,
        string $label = '',
        $value = 1,
        $bind = null,
        bool $default = false,
        bool $showErrors = false
    ) {
        $this->name       = $name;
        $this->label      = $label;
        $this->value      = $value;
        $this->showErrors = $showErrors;

        $inputName = static::convertBracketsToDots($name);

        //modified line
        if (!is_null(old($inputName))) {
            //modified line
            $this->checked = $this->toStringIfFalse(old($inputName)) == $value;
        }

        if (!session()->hasOldInput() && $this->isNotWired()) {
            $boundValue = $this->getBoundValue($bind, $name);

            if (!is_null($boundValue)) {
                //modified line
                $this->checked = $this->toStringIfFalse($boundValue) == $this->value;
            } else {
                $this->checked = $default;
            }
        }
    }

    /**
     * Generates an ID by the name and value attributes.
     *
     * @return string
     */
    protected function generateIdByName(): string
    {
        return "auto_id_" . $this->name . "_" . $this->value;
    }

    /**
     * All of the non-string boolean values considered false are casted to string
     * so that it can be correctly compared with the input radio value
     * (string values considered false like "0" or "" are already correctly compared)
     * 
     * @return string
     */
    protected function toStringIfFalse($value)
    {
        if($value === false ||
           $value === 0 ||
           $value === 0.0 ||//im not sure this one
           $value === -0.0 // and this one will find concrete cases...
        ){
            return var_export($value, true);
        }
        return $value;
    }
}
pascalbaljet commented 3 years ago

I think this is the same issue as #58. I'll take a look at it soon!

pascalbaljet commented 3 years ago

Fixed in v3.1.0.

supergreentony commented 2 years ago

Fixed in v3.1.0.

Validated! Thank you @pascalbaljet this is a must-have component! ;)