There are many many questions here on SO about how to properly persist checkbox fields in Laravel after form submission (
example,
example,
example
), this question is not about that.
Please note I am also well aware of Laravel's old() method, and that it accepts a default value. My question is about a particular case where old() does not seem to work for a checkbox.
I'm working on an edit form, updating data already in the DB. The form will initially be populated with the values from the DB.
The standard approach to re-populating form inputs after failed validation is to use old(). For most input types, something like the following works:
<input type='text' name='unicorns' value='{{ old('unicorns', $model->unicorns) }}'>
On initial page load (before the form is submitted) this works fine. As nothing has been submitted yet, old('unicorns') is null, so the default of $model->unicorns will be used, and the text field's value reflects the current DB state.
After submitting a new value, which fails validation, old('unicorns') will be the new value, even if the new value was an empty string, and again the text field's value reflects the submitted state, as we want.
However this breaks down for checkboxes, when the unchecked checkbox does not appear in the request at all. Consider:
<input type='checkbox' name='unicorns' value='1' #if old('unicorns', $model->unicorns) checked #endif>
On initial page load this works fine, just like for text fields. But after failed validation, for the 2 cases where the checkbox is changed from its initial state:
Case 1: DB state 0 (unchecked), submitted state checked. old('unicorns') will be 1, so the test evaluates true, the checkbox is checked - OK!
Case 2: DB state 1 (checked), submitted state unchecked. Since old('unicorns') is null, old() falls back to the default value $model->unicorns (1), so the test evaluates true, and the checkbox is checked - but we just unchecked it! FAIL!
(There is no problem in the other 2 cases, where the checkbox is not changed from the state in the DB).
How to solve this?
I initially thought the best way around this would be to test if there has been a validation error - if so, use the old() value, with no default fallback; if not, use old() with default fallback. One way to test for failed validation is to check $errors. This seems to work, but it only works within a view AFAICT, as (from the Laravel docs):
Note: The $errors variable is bound to the view ...
I'd like to create a global helper for this, and $errors won't work there. Anyway, this approach feels ... clunky and too complicated.
Am I missing something? Is there a neat Laravel way of solving this? It seems odd that old() simply does not work for this particular case.
This is not a new problem, how do others handle this?
This is the solution I referred to in my question. It works well, and 6 months later, it does not seem as clunky as when I posted the question. I'd be happy to hear how others are doing this though.
I have an Html helper, created as described in this question, and aliased in config/app.php as described in the first part of this answer to that question. I added a static method to it:
namespace App\Helpers;
use Illuminate\Support\ViewErrorBag;
class Html {
/**
* Shortcut for populating checkbox state on forms.
*
* If there are failed validation errors, we should use the old() state
* of the checkbox, ignoring the current DB state of the field; otherwise
* just use the DB value.
*
* #param string $name The input field name
* #param string $value The current DB value
* #return string 'checked' or null;
*/
public static function checked($name, $value) {
$errors = session('errors');
if (isset($errors) && $errors instanceof ViewErrorBag && $errors->any()) {
return old($name) ? 'checked' : '';
}
return ($value) ? 'checked' : '';
}
}
Now in my views I can use it like so:
<input type='checkbox' name='unicorns' value='1' {{ \Html::checked('unicorns', $model->unicorns) }}>
This correctly handles all combinations of DB and submitted state, on initial load and after failed validation.
I came across the same problem and found this old post. Thought to share my solution:
<input type="checkbox" name="unicorns" class="form-check-input" id="verified" {{ !old()?$model->unicorns:old('unicorns')?' checked':'' }}>
{{ !old()?$model->unicorns:old('unicorns')?' checked':'' }}
Nested ternaries: The first ternary provides the condition for the second:
When there is no old() array, there is no post, thus the DB value $model->unicorns will be used as the condition like so:
{{ $model->unicorns?' checked':'' }} will correctly evaluate on a value of either 0 or 1
If however old() array is present, we can use the existence of the old('unicorns') variable as the condition like so:
{{ old('unicorns')?' checked':'' }} will correctly evaluate on a value of on or no value.
It's a bit of type juggle and you have the nested ternary, but it works well.
I had a similar situation and my solution was to add a hidden field just before the checkbox field. So, in your case it would be something like:
<input type='hidden' name='unicorns' value='0'>
<input type='checkbox' name='unicorns' value='1' {!! old('unicorns', $model->unicorns) ? ' checked' : '' !!}>
That way, when the checkbox is not ticked, a value of 0 for that field will still be present in the post request. When it is ticked then the value of the checkbox will overwrite the value in the hidden field, so the order is important. You shouldn't need to use your custom class with this approach.
Does that work for you?
From Don't Panic 's answer, you could do it like this in blade:
<input type="checkbox" class="form-check-input" value='true'
#if ($errors->any())
{{ old('is_private') ? 'checked' : '' }}
#else
{{ isset($post) && $post->is_private ? 'checked' : '' }}
#endif
>
Hope it helps.
I do this
<input id="main" class="form-check-inline"
type="checkbox" name="position" {{old('position',$position->status)?'checked':''}}>
I actually do a simple ternary operator when persisting checkbox states:
<input name='remember' type='checkbox' value='1' {{ old('remember') ? 'checked' : '' }}>
Edit:
<input name='remember' type='checkbox' value='yes' {{ old('remember') == 'yes' ? 'checked' : '' }}>
Related
I'm trying to do something that allows me to upload photos when I check a checkbox control. I got the client side working correctly such that when the checkbox is checked the upload controls are displayed and the form validates correctly.
However, in my controller I need to take some action if my checkbox was checked (true) calling a certain method. If it isn't checked (false) I perform some other action.
In my html page I have the following:
<form action="/supplier/submit/plan" method="post" role="form" id="plan-form">
...
<input name="checkingPhotos" type="checkbox" id="chkPhotos" />
<label for="chkPhotos">I want to include photos in this plan.</label>
...
</form>
However, in my controller I just want to for now see if I get the correct value in my checkbox. For this I did something simple as:
public function submitPlan(Request $request)
{
$checkboxValue = $request->input('checkingPhotos');
dd($checkboxValue);
}
The result is null is printed whether I check the checkbox or not. My route also looks like this:
Route::post('/submit/plan', 'SupplierController#submitPlan');
Can someone please tell me what I am doing wrong here? I just want to see the value 1 / True or 0 / False in my controller method.
Value
The real issue is that you don't have a value for your check box. Add a value, and your problem is solved. It should be:
<input name="checkingPhotos" type="checkbox" id="chkPhotos" value="1" />
[] creates an array
The answer Dylan Kas submitted about changeing the name to add [] works, but not for the reasons you think. Lets take a look:
<input name="checkingPhotos[]" type="checkbox" id="chkPhotos" />
Will pass in the post string:
checkingPhotos[]=On
Which, in PHP will automatically be turned into an array.
Refernce Frame Challenege
Why do you have a checkbox in the first place? Is the checkbox needed? Why not just check for the existence of the file.
$validated = $request->validate([
//... other fields here.
'image' => 'mime:png,gif,jpeg|max:10000' //set max to file size limit you want
]);
$plan = new SupplierPlan($validated);
if($request->has('image')){
$plan->image = $request->image->store();
}
$plan->save();
// ... flash message, return view or redirect
If it's a checkbox you should modify the name of your input to
<input name="checkingPhotos[]" type="checkbox" id="chkPhotos" />
Then you should be able to get the value as you want it with
$request->input('checkingPhotos');
It seems your problem is in your route, change it to
Route::post('/supplier/submit/plan', 'SupplierController#submitPlan');
I have a checkbox in my form which looks like this:
<input class="form-control" type="checkbox" id="showCTA" name="showCTA" <?php echo $block['showCTA'] ? 'checked' : ''; ?> />
Everything works fine with this mark up....unless the PHP value equals 1(already checked). If this is the case, I can check and uncheck the box in the from end visually, but the actual html attribute does not change resulting in the same value of 1 being saved to my database on submit.
How can I work around this in a clean manner? I assume the issue is since the PHP value is absolute until submitted, it means the condition around my "checked" attribute is also absolute, therefore I cannot change the attribute.
If the checkbox is not checked and you post the form, the $_POST['showCTA'] will be undefined. So you should use the isset($_POST['showCTA']) method which will return true if the checkbox is checked and if not, false.
I'm trying to make a form partial that can be reused for both INSERT and UPDATE. I'm stuck on populating checkboxes. Here what I have:
<input type="checkbox" id="Paid" value="1" name="Paid"
{{ (old('Paid') ?? $invoice->Paid ?? false) ? 'checked' : '' }} />
It works for when loading the form the first time on both new records and updating. The problem is when a user unchecks the box when editing a record but something else on the form fails validation. When the form loads after failed validation the box that was unchecked is checked again. The database value from $invoice->Paid is loaded because the old() returns false.
You should be able to do this like so:
{{ old('Paid', $invoice->Paid) ? 'checked="checked"' : '' }}
As long as the old value was true, or the Paid property of the $invoice model is not null/false, then it will apply the checked value, else it will not.
I tried for hours to get this working. In the end I gave up and installed LaravelCollective HTML package:
https://laravelcollective.com/docs/5.3/html
Form model binding in this package works for populating checkboxes in the above scenario.
One approach is to test the value of old('_token'):
#if (!(old('_token') && $invoice->Paid) || (old('Paid')))
checked
#endif
I want to show the old input in input value. If there isn't old input, than show other variable:
value="{{ old('salary_' . $employee->id) or 'Default' }}"
But when there is no old input, it gives me 1 instead of the default value!
I think the problem has something to do with the concatenation, but I don't know how to fix it!?
or is a comparison operator in PHP, so your code is evaluating to true, or 1. What you want is a ternary if statement.
As mentioned, or can be used in blade as shorthand for a ternary if statement.
But you can (and should) just pass the default value as the second argument to the function, like so:
value="{{ old('salary_' . $employee->id, 'Default') }}"
You can use the code (for PHP 7):
{{ old('field_name') ?? $model->field_name ?? 'default' }}
For checkbox checked attribute use the code (if default value is false):
{{ (old() ? old('field_name', false) : $model->field_name ?? false) ? 'checked' : '' }}
Construction {{ $something or 'default'}} works only for variables
You can use:
old($key, $defaultValue)
See more:
https://github.com/laravel/framework/blob/87df108bb487714d205002aba7e7317533976a8d/src/Illuminate/Foundation/helpers.php#L541-L553
As described in the Laravel doc: "If you are displaying old input within a Blade template, it is more convenient to use the old helper:".
So if you need add/edit data form (when you need to use edit form for add and edit in edit mode you need to use loaded data from model (database)) to show values from the model (through controller) you can use following:
name="some_value" value="{{ $some_value or old('some_value', $the_value) }}"
where is "some_value_from_model" variable name in view array.
In this case it should be at first $some_value will be used to set in the "value" and, if no, it will try to use old (value from request from name "some_value") and if not old then '' should be used.
Thanks WoodyDRN for comment.
Try this:
value="{{ old('salary_' . $employee->id) ?? 'Default' }}"
Explanation:
If an old value is there, it will be set, otherwise, 'Default' will be set as value.
Try this:
<textarea name="alamat" id="" class="form-control" placeholder="Alamat">{{ old('alamat').#$biodata->alamat }}</textarea>
I am pulling data down from a MySQL table and loading it into a form for editing(updating) a record. Everything is working great until I come the the check boxes. The checkboxes in the form accurately reflect the values in the appropriate columns in the db. But when the person editing changes the checkbox in the edit form it does not pass the data to the database. I have read a ton of checkbox Q&A on stack overflow but don't seem to find what I am looking for. Sorry if this is a redundant Question. Here is the code.
<label for="amenities-beach">
<input class="choose" name="amenitiesB" id="amenities-beach" type="checkbox"
value="<?php echo $row1["amenitiesB"]; ?>"
<?php echo $row1["amenitiesB"] ? 'checked="checked"' : ''; ?> />
Close to Beach</label>
Where amenitiesB in:
value="<?php echo $row1["amenitiesB"]; ?>
is what has been returned from the DB with a SELECT statement with:
$row1 = mysql_fetch_array($result);
But when I change the value in the form and submit it nothing is passed to the variable in the UPDATE statement. Any idea what I am missing? I have 6 of these checkboxes,amenitiesB, amenitiesK, amenitiesS, amenitiesP, amenitiesF, and preferred all with the same code. Any help would be appreciated.
Thank You,
Dave
Ok here is the code: Everything else in the form updates fine. I attempt to pass it to:
$amenitiesB = $_POST['amenitiesB'];
then I put it into the update statement
Hotels.amenitiesB='".$amenitiesB."',
My UPDATE statement is,
$query="UPDATE Hotels
JOIN surfcup_Rates ON Hotels.id = surfcup_Rates.hotelid
SET Hotels.hotel='".$hotel."',
More columns, then
Hotels.amenitiesB='".$amenitiesB."',
Hotels.amenitiesB='".$amenitiesK."',
Hotels.amenitiesB='".$amenitiesS."',
Hotels.amenitiesB='".$amenitiesP."',
Hotels.amenitiesB='".$amenitiesF."',
Hotels.amenitiesB='".$preferred."',
More columns then:
WHERE Hotels.id='".$id."'";
The problem you have comes because when a checkbox is unchecked, by default its data is not transmitted to your PHP, and that's why you have problems by having the UPDATE query parameter empty.
So before your update statement you should have:
$fieldenabled=(bool)(isset($_POST['CHECKBOXNAME']) ? TRUE : FALSE;
And call your UPDATE query with that.
EDIT: Of course you can change $_POST with $_GET depending on the sending method of the <form>
Edit: I think I get the problem. When the box is initially unchecked, the input has an empty value, then when you check it, it passes an empty value in... it will never fill with what you intend the checked value to be. So, instead you need something like this:
<input class="choose" name="amenitiesB" id="amenities-beach" type="checkbox" value="amenity B Selected" <?php echo $row1["amenitiesB"] ? 'checked="checked"' : ''; ?> />
... don't make the "value" attribute dynamic, or else once it becomes empty it will always be empty.
Original Answer:
I assume when you say "change the value in the form" you mean that you uncheck the checkbox... unchecked checkboxes never send any data when you submit the form. You check for "unchecked" status by checking to see if the form variable has been passed at all.
For example:
if (isset($_GET['amenitiesB'])) {
// process with the knowledge that "amenitiesB" was checked
}
else {
// process with the knowledge that "amenitiesB" was unchecked
}
If you mean that you somehow dynamically change the "value" of the checkbox to something else, then I'll need to see the code that accomplishes that.
The main purpose of the "value" attribute in a checkbox input is when you're passing the variable as an array:
<label for="amenities-beach">
<input class="choose" name="amenities[]" id="amenities-beach" type="checkbox" value="<?php echo $row1["amenitiesB"]; ?>" <?php echo $row1["amenitiesB"] ? 'checked="checked"' : ''; ?> />
Close to Beach
</label>
... note specifically that I've changed the "name" attribute from "amenitiesB" to "amenities[]", which, if carried through all of your amenities checkboxes, will give you access to them all in your processing script through the $_GET['amenities'] array (or $_POST, if applicable). Otherwise, there's not much reason to use the "value" attribute of the checkbox input, because you can get all you need just by knowing $_GET['amenitiesB'] is checked (and thus sent with the form) or unchecked (and not sent with the form).