Framework: More elegant handling of unchecked checkboxes

Created on 5 Jul 2016  路  9Comments  路  Source: laravel/framework

I know that HTTP does not send a value if a checkbox or radio button is unchecked, but for the sake of consistency and simplicity, I'd like to suggest that Laravel always synthesizes this value if necessary when processing the POST data so that the client only has to handle the cases false and true for each button.

As it is now, you have to do silly checks in your code to see if a checkbox has been set or not set, instead of simply using the value (false or true).

Right now I have code like this in my controller's store method:

'''

public function create_post(ContactFormRequest $request)
{
    $checkboxes = [ 'member', 'public_advisor', 'family_advisor', 'patient_advisor', 'other' ];

    $columns = Schema::getColumnListing('contacts');
    $values  = [];
    foreach ($columns as $column)
    {
        // Incrementing field, cannot be set.
        if ($column == 'contact')
            continue;

        // Handle checkboxes specially because HTML::FormBuilder doesn't help us.
        if (in_array($column, $checkboxes))
            $value = ($request->input($column, false) ? 1 : 0);
        else
            $value = $request->input($column);

        $values[$column] = $value;
    }

    $contact = new Contact($values);
    $contact->save();

    return redirect('contact/create')->with('message', 'Kontakt oprettet');

}

'''

I can see that many others on the 'net have similar issues and all sorts of incorrect and partially bogus fixes are suggested. This should be solved at the source, i.e. the HTML Form builder, not in 20,000 different apps using more or less incorrect hacks.

P.S. This issue was first posted at LaravelCollective/HTML builder but they rightly pointed out that they only generate HTML and therefore are not in control of the button's POST value.

Most helpful comment

Right now the best solution I know is adding hidden field above the checkbox with 0 value.
So when the checkbox is unchecked it will send hidden field. But I think such solution is solving on the HTML form builder side.

<input type="hidden" name="notifications" value="0">
<input type="checkbox" name="notifications" value="1" checked>

All 9 comments

Right now the best solution I know is adding hidden field above the checkbox with 0 value.
So when the checkbox is unchecked it will send hidden field. But I think such solution is solving on the HTML form builder side.

<input type="hidden" name="notifications" value="0">
<input type="checkbox" name="notifications" value="1" checked>

I read somewhere that there are issues with adding a hidden field. I'll try to see if I can find it again, but this solution is not as good, IMHO, as synthesizing a boolean value when processing the POST data. As far as I recall, the hidden button method creates problems if you resubmit a form.

The problem is described here:

http://laravel.io/forum/09-26-2014-handling-unchecked-checkbox-by-updating

The problem is that if the form fails validation, the hidden method fails to work on the 2nd go around.

Also, the comments on this page says that it is invalid XHTML, which I happen to use:

http://nielson.io/2014/02/handling-checkbox-input-in-laravel/

It is down in the comments in a comment submitted by "carl".

Why was this issue closed? It's still a problem as far as I can tell.

@sitelifters I think this issue could go in laravel/internals before the right solution wouldn't been found.

Are there any Vendor libraries that tackle this issue?

My solution:

Model

    public $checkboxes;//To not have redundancy of the same information in the controller

    protected $fillable = [
            'name','che1', 'che2', 'che3', 'che4', 'che5', 'che6', 'che7', 'cheN'
    ];

    public function __construct(array $attributes = array())
    {
            parent::__construct($attributes);

            $this->checkboxes = array_diff($this->fillable, ['name']); //Here are the ones that are not checkboxes
    }

Controller

    public function post(Request $request)
    {
            //validation
            \App\Model::create($request->all());
            return redirect()->route('route.new')->with('sucess', true);
    }

    public function put(Request $request, $id)
    {
            //validation
            $model = \App\Model::find($id);
            foreach ($model->checkboxes as $checkbox) {
                    $model->setAttribute($checkbox, false);
            }
            $model->update($request->all());
            return redirect()->route('route.list')->with('sucess', true);
    }

that works fine if you only have 1 form submitting to that endpoint, which is passing every field for that model.

it causes issues when you have requests which dont pass every field, all of your checkbox fields get reset to false

personally i use the hidden field with same name method and havent had any issues with it

Was this page helpful?
0 / 5 - 0 ratings

Related issues

CupOfTea696 picture CupOfTea696  路  3Comments

SachinAgarwal1337 picture SachinAgarwal1337  路  3Comments

Anahkiasen picture Anahkiasen  路  3Comments

gabriellimo picture gabriellimo  路  3Comments

felixsanz picture felixsanz  路  3Comments