babai9's avatar

old() value of checkbox, with the one from the database, along with if old remains empty laravel

I want to submit a checkbox with update for which I am using this code and it's working fine

<div class="form-row">

                                        <?php 
                                            $amenityMo = \App\Models\Amenity::orderBy('amenity_name','ASC')->get();
                                            $amenity = $amenityMo->split($amenityMo->count()/1);
                                        ?>

                                        @foreach($amenity as $row)

                                            <div class="col-md-2 mb-2">

                                                @foreach($row as $j => $amenityCl)


                                                    
                                                    <div class="form-check">
                                                      <input class="form-check-input" type="checkbox" value="{{ $amenityCl->id; }}" name="amenities[]"  @if(old('amenities') !== null) @checked(in_array($amenityCl->id, old('amenities', []))) @else @checked(in_array($amenityCl->id, $propertyAmenityArr)) @endif  id="defaultCheck{{ $amenityCl->id; }}">
                                                      <label class="form-check-label" for="defaultCheck{{ $amenityCl->id; }}">
                                                        {{ $amenityCl->amenity_name; }}
                                                      </label>
                                                    </div>
                                                    <?php $j++; ?>
                                                @endforeach

                                            </div>


                                        @endforeach

                                        @if($errors->has('amenities'))
                                            <div class="error text-danger fs-6">{{ $errors->first('amenities') }}</div>
                                        @endif

                                    </div>

My controller

$propertyAmenityArr = array();
        $propertyAmenity = PropertyAmenity::select('amenity_id')->where('property_id',$id)->where('status',0)->get();
        foreach ($propertyAmenity as $key => $value) {
            $propertyAmenityArr[] = $value->amenity_id;
        }
return view('pro.edit',compact('propertyAmenityArr'));

The problem is that the second parameter you give the the old() function is used when the first value is null. So when you do old('amenities', $propertyAmenityArr) and no old value for 'amenities' is found, $propertyAmenityArr is used. So I want it to write in such a way that the codes work even if there is no old value for 'amenities' is found, means it should remain unchecked. I figured out three possibilities in it

  1. if old() has the value should get checked.
  2. if $propertyAmenityArr has the value should get checked
  3. if checkbox is unchecked should remain unchecked
0 likes
34 replies
Snapey's avatar

with

old('amenities', $propertyAmenityArr) 

$propertyAmenityArr should be an array of the existing property amenities. If there are not any because the object is new then it should be set to an empty array.

babai9's avatar

@Snapey I did this but the issue is when the edit page loads then it takes what is $propertyAmenityArr array, okay, then if I choose any other option then 'amenities' array okay but if now I am choosing nothing then it takes the values available in $propertyAmenityArr, but it should be empty as I have chosen nothing, this field I can't make required as it is not in requirement, it should be nullable field, means can be empty submitted, so it is making hard for me to find out how to show empty

babai9's avatar

@Snapey $propertyAmenityArr it is an array which contains me database values, into my create segment while I am adding the data old('amenities', []) this is I am using and it is working fine, even though I leave empty, the issue is with my edit part

Snapey's avatar

@babai9 Your edit values comes from the database (selected amenities from database)

If the form is saved with no checkboxes selected then the database should be updated with no amenities

Then, when the PropertyAmenitiesArr is assembled for the edit view then it should be an empty array.

babai9's avatar

@Snapey no you got me wrong PropertyAmenitiesArr this is my value from database 'amenities' this is my field name which is an array everything is fine If the form is saved with no checkboxes selected then the database should be updated with no amenities correct but suppose I have some other fields also so when they have errors I am showing them below their respective fields, at that time when the form is submitted the page is reloaded and it shows the error below those fields at that time the user who already unchecked the checkbox he sees that those are checked due to those errors in other fields at that time I need to show those unchecked boxes to be unchecked

Snapey's avatar

@babai9 This is where the first part of the old() helper comes in. If the form submission has errors then the session will contain the old values and these will be used in preference to the array from the database.

babai9's avatar

@Snapey so do you know how can I do what do I want to do? I searched and looked into the forums for long but couldn't find a solution.

Snapey's avatar

@babai9 It should work as you have it but without seeing the controller and the foreach loop, its hard to say

you could try dumping old('amenities') before you loop over the checkboxes and see if it contains the IDs you expect after validation errror

babai9's avatar

@Snapey I have updated to your requirements, can you please check now

Snapey's avatar

@babai9 i dont recognise any if the changes you have made and you are probably further away from the solution

all I wanted you to add was @dump(old('amenities')) before the foreach loop

babai9's avatar

@Snapey okay sure i have done that too at one time I get and the other time dont see the array

babai9's avatar

When any checkbox is checked array:3 [▼ 0 => "14" 1 => "21" 2 => "22" ]

and when no checkbox checked i got null but checkboxes are checked with the database values

babai9's avatar

The concern was the same like before if in old there is values its working perfectly, but if old doesnot have values or is null then it takes the database values but it shouldn't as I haven't checked anything.

Snapey's avatar

Your controller@babai9 should be

$propertyAmenityArr = PropertyAmenity::where('property_id',$id)
			->where('status',0)
			->pluck('amenity_id');

$allAmenities = Amenity::orderBy('amenity_name','ASC')->get();

return view('pro.edit',compact('propertyAmenityArr','allAmenities'));

and then the view

<div class="form-row">
    @foreach($allAmenities as $amenity)
        <div class="form-check">
            <input class="form-check-input" type="checkbox" 
                id="amenity-{{ $amenity->id }}"
                value="{{ $amenity->id }}" name="amenities[]"
                @checked(in_array($amenity->id, old('amenities', $propertyAmenityArr))) />
            <label class="form-check-label" for="amenity-{{ $amenity->id }}">
                {{ $amenity->amenity_name; }}
             </label>
        </div>
    @endforeach
</div>
babai9's avatar

@Snapey This is not going to work while my old values are null, i did what you recommended but it is working like mine only

Snapey's avatar

@babai9 you just need to get your head around the way it works

if you show edit for the first time it will reflect the state of the database

if you change some flags but then get a validation error old will return an array of ids that were selected when you submitted the form. If none of the checkboxes were selected then old will return an empty array.

If it is not doing this then maybe you are doing something odd in validation

Snapey's avatar

@babai9 there is a big difference between old values being null and being an empty array.

This method works perfectly for everyone else?

babai9's avatar

@Snapey yes you are right, if I can add validation it works perfect, but the issue is I can't add any validation to it as I mentioned it can be empty too.

babai9's avatar

@Snapey It's not working while old values are null and you can't put in validation

Snapey's avatar

@babai9 old values will only be null when you are loading the page for the first time. When returning from validation error, old will be an array of the selected values, even if that array is empty. (note empty array, not NULL)

It does not matter if you are validating the checkboxes or not.

Show your validation method?

babai9's avatar

@Snapey I have nothing to show in it rather than this

$request->validate([   
            
            '_token' => 'required',
            'title' => 'required|string',
]);

so if i dont put the title it shows me the error of title required below title field, at that time if checkboxes aren't checked then it gives me the checked values from database but it should be unchecked as it has nothing now

Snapey's avatar
Snapey
Best Answer
Level 122

@babai9 OK, I see your issue.

The problem that is unique to checkboxes is that they are not sent at all when not checked.

So when you submit the form with all checkboxes cleared, then there is no old('amenities') value at all because it is not part of the form data. Its not related to the PR you linked to. When there is no old value then the defaults are used.

One option is to include a hidden field that is always sent.

somewhere in your form, before the checkboxes;

input type="hidden" name="amenities[]" />

This will always be included, so when saving the results to the database you may need ignore any null member of the array.

edit: an improved option

input type="hidden" name="amenities" /> // no square braces

and

@checked(in_array($amenity->id, old('amenities', $propertyAmenityArr) ??[])) />

The null safe operator is used for the case were the previous form submission was all checkboxes cleared in which case the hidden field is used and causes old amenities to be null. The nullsafe operator swaps this for an empty array.

The benefit of the edit version is that the hidden field is not present when some checkboxes are checked.

babai9's avatar

Finally I got @snapey some suggestions I took from yours and from this reply https://laracasts.com/discuss/channels/laravel/blade-check-if-old-values-are-empty-or-not#reply-576093 so here is my view now

<div class="col-md-2 mb-2">
@php
 $old_amenities = (old('_token') !== null) ? collect(old('amenities')) : $propertyAmenityArr;
  @endphp
@foreach($row as $j => $amenityCl)
 <div class="form-check">
         <input class="form-check-input" type="checkbox" value="{{ $amenityCl->id; }}" name="amenities[]" id="defaultCheck{{ $amenityCl->id; }}" @if($old_amenities->contains($amenityCl->id)) checked @endif>
          <label class="form-check-label" for="defaultCheck{{ $amenityCl->id; }}">{{ $amenityCl->amenity_name; }}</label>
</div>
<?php $j++; ?>
@endforeach
 </div>

and in my controller

$propertyAmenityArr = PropertyAmenity::where('property_id',$id)
			->where('status',0)
			->pluck('amenity_id');

$allAmenities = Amenity::orderBy('amenity_name','ASC')->get();

return view('pro.edit',compact('propertyAmenityArr','allAmenities'));

It's now working perfectly. Thank you for being there with me @snapey.

Snapey's avatar

@babai9 I don't like the fact that you rely on the previous csrf token to tell you if this is a first time load or a re-load. Seems brittle, and as I posted, is not necessary. Neither is checking for the presence of _token in your validation rules.

1 like
Snapey's avatar

@babai9 this line

<?php $j++; ?>

does nothing since you don't use $j anywhere

1 like
babai9's avatar

@Snapey but really I didnot found any other way out of it, to meet my requirements, j++ part I removed, really I was thinking of doing something out of it, i think its okay as without csrf token I am logging them out as you cant take risk, they need to submit form with csrf only, so in that case yes _token is not required in validation.

Snapey's avatar

@babai9 > but really I didnot found any other way out of it

Did you not see my reply before your solution? I think we posted at the same time

babai9's avatar

@Snapey The requirements were not fulfilled totally your controller process was great I used it and it was fine, but in views I was stucked really and exhausted, but although got something

Snapey's avatar

@babai9 I mocked all your code and proved that my solution using a hidden field works fine.

hopefully others will see my answer before yours and use it.

babai9's avatar

@Snapey can you share the controller and view of how you are doing? You are right I want to use the best way the way I did is not accepted to me, although it solved my issue.

Snapey's avatar

@babai9 just read my reply above, there is only one line added to the view. No change in the controller

babai9's avatar

@Snapey Correct this way can be done and its the best way out but for this you have to use array method in controller

Please or to participate in this conversation.