Looping through input array in Laravel 5 - php

I have a basic UI where users can add a simple list with a label and a value. I want to loop through that list to store the data in a "Detail" model.
I have the following code.
Controller:
$details = $request->input('detail_label');
foreach($details as $key => $value)
{
if(!empty($request->input('detail_value.'.$key))) {
// if the detail has an existing ID
if($request->input('detail_id.'.$key)) {
$detail = Detail::find($request->input('detail_id.'.$key));
} else {
$detail = new Detail;
}
$detail->type = $request->input('detail_type.'.$key);
$detail->label = $request->input('detail_label.'.$key);
$detail->value = $request->input('detail_value.'.$key);
if($request->input('detail_privacy.'.$key) == 1) {
$detail->privacy = 1;
} else {
$detail->privacy = 0;
}
$user->details()->save($detail);
}
}
View:
#foreach($user->details as $detail)
<div class="detail">
<input type="hidden" name="detail_id[]" value="{{ $detail->id }}">
<label>Type
<select name="detail_type[]">
<option #if($detail->type == '1')selected #endif value="1">Phone</option>
<option #if($detail->type == '2')selected #endif value="2">Phone (mobile)</option>
<option #if($detail->type == '3')selected #endif value="3">URL</option>
<option #if($detail->type == '4')selected #endif value="4">Email</option>
</select>
</label>
<label>Label
<input type="text" name="detail_label[]" value="{{ $detail->label }}">
</label>
<label>Value
<input type="text" name="detail_value[]" value="{{ $detail->value }}">
</label>
<label>Private?
<input type="checkbox" name="detail_privacy[]" #if($detail->privacy == true) checked #endif value="1">
</label>
<label>Delete?
<input type="checkbox" name="detail_delete[]" value="{{ $detail->id }}">
</label>
</div><!-- / detail -->
#endforeach
Every aspect of my code works as I had planned except the detail_privacy field. It sets and unsets the boolean privacy attribute but it pays no attention to which $key I want. It always sets it according to the order in the loop. If I just set one detail to be private it will be first. If I set two, (whichever two), it will be the first and second.
Something is clearly wrong with my logic but I can't tell what.
Any help would be really appreciated. Thanks!

The reason it doesn't work is that non-checked checkboxes are not included in the post data. You may see it by dumping value of $request->input('detail_privacy').
To be able both to edit existing and add new details, you need to set keys on inputs in the form. Anything really, as long as you keep track of it. To make things easier you can add hidden input named same as the checkbox, so detail_privacy will be always present in the post data. For example:
#foreach ($user->details as $key => $detail)
<input type="hidden" name="detail_id[{{ $key }}]" value="{{ $detail->id }}">
...
<input type="hidden" name="detail_privacy[{{ $key }}]" value="0">
<input type="checkbox" name="detail_privacy[{{ $key }}]" #if($detail->privacy == true) checked #endif value="1">
...
#endforeach
If you add new fields dynamically ie. with javascript you need to respect those keys. Its quite simple though, just pass last value of $key to your js and you're set.
Also I would recommend different notation for input names: details[{{ $key }}][id] instead of detail_id[{{ $key }}]. This way controller action will become much simpler:
foreach ($details as $detail) {
if (! empty($detail['id'])) {
...
}
}

If the Boolean values are stored as TINYINTS in the Database (as in: 0 or 1); then perhaps taking out the Boolean true || false may resolve the Issue. Not Certain but guessing it's worth the try:
<!-- JUST TRY IT LIKE SO: #if($detail->privacy) checked #endif -->
<label>Private?
<input type="checkbox"
name="detail_privacy[]"
#if($detail->privacy) checked #endif value="1"
>
</label>
Or Hypothetically:
<!-- YOU MAY ALSO USE "1" LIKE SO: #if($detail->privacy==1) checked #endif -->
<label>Private?
<input type="checkbox"
name="detail_privacy[]"
#if($detail->privacy==1) checked #endif value="1"
>
</label>

Related

Update status in database using checkbox - Laravel

The project can have different statuses. With the checkbox, I am trying to switch the status of the project from requested (1) to accepted (2). If the checkbox is unchecked the status is 1, checked it's 2.
When I check the checkbox I got a 419 but this is normally related to the token but I added a #csfr field. Why is the status not changed in the database?
Thanks for any help.
index.blade.php (summary of all the projects)
#foreach ($projects as $project)
<tbody>
<tr>
<form action="/projects/plan" method="post" id="statusForm">
#csrf
<input name="id" type="hidden" value="{{$project->id}}">
<td>
<input type="hidden" value="{{$project->status}}" name="status">
<input {{isset($project['status']) && $project['status'] == '2' ? 'checked' : ''}}
value="{{$project->status}}" type="checkbox" name="status"
onchange="document.getElementById('statusForm').submit()"
>
</td>
</form>
<td>{{$project->applicant_name}}</td>
<td>{{$project->project_name}}</td>
<td>Project Details</td>
</tr>
</tbody>
#endforeach
Project.php (functions to update status)
const STATUS_requested = 1;
const STATUS_ACCEPTED = 2;
public function updateStatus( $status )
{
$this->update([
'status' => $status
]);
$this->refresh();
return $this;
}
public function projectAccept() {
return $this->updateStatus( self::STATUS_ACCEPTED );
}
ProjectsController.php (dd('hello') is not printed it seems like data is not sent to this resource)
public function plan(Request $request)
{
dd('hello');
Event::find($request->id)->projectAccept();
return Project::STATUS_ACCEPTED;
}
web.php
// Update status project
Route::post('/projects/plan', 'ProjectsController#plan');
First, you cant select by ID document.getElementById('statusForm').submit() when you have multiple DOMS with the same ID.
change your loop to something like this
#foreach ($projects as $project)
<tbody>
<tr>
<td>
<form action="/projects/plan" method="post" id="statusForm{{$project->id}}">
#csrf
<input name="id" type="hidden" value="{{$project->id}}">
<input {{isset($project['status']) && $project['status'] == '2' ? 'checked' : ''}}
value="2" type="checkbox" name="status"
onchange="document.getElementById('statusForm{{$project->id}}').submit()"
>
</form>
</td>
<td>{{$project->applicant_name}}</td>
<td>{{$project->project_name}}</td>
<td>Project Details</td>
</tr>
</tbody>
#endforeach
Now, a checkbox will only be sent in a form when it is checked, so no need for a variable value for that input
<input {{isset($project['status']) && $project['status'] == '2' ? 'checked' : ''}}
value="2" type="checkbox" name="status"
onchange="document.getElementById('statusForm{{$project->id}}').submit()"
>
Finally, when you recover the input status, set a default value for the unchecked one (you can remove the hidden input with this one). Or as you did, set a hidden input with the original value to be sent every time. Both solution are perfect.
public function plan(Request $request)
{
$status = $request->input('status', Project::STATUS_requested);
Event::find($request->id)->projectAccept();
return Project::STATUS_ACCEPTED;
}
That way if it is checked it will be 2 (in the request) and if not, it will be 1 from the default value.

inner foreach loop check if condition and break only inner loop in php

I have two foreach loop nested, I only want the inner loop to check the condition. If it satisfies or not either one, then terminate the inner loop and come back to the outer loop.
In my condition, the inner loop always needs to run once as I understand my Problem.
Problem: Two arrays. First having all options. Second having only selected. Now math the id. If matched=> Print checked, Else => UnChecked.
I have tried the break; but inner loop only check 1st item then all iteration in else part executed.
#php
foreach($propertyAmenities as $amenity){
foreach($property->amenities as $new){
if( ($amenity->type == 'amenity') && ($amenity->id == $new->id) ){
#endphp
<label class="checkbox-inline control-label">
<input type="checkbox" name="amenity[]" value="{{$amenity->id}}" {{'checked'}}>{{ $amenity->name }}
</label>
#php break;
}
elseif(($amenity->type == 'amenity')){ #endphp
<label class="checkbox-inline control-label">
<input type="checkbox" name="amenity[]" value="{{$amenity->id}}">{{ $amenity->name }}
</label>
#php break;
}
}
}
#endphp
First time it checks and print 'checked' next time its only execute ifelse part. i dont know why
only first is checked.
all else remain Unchecked.
You can simplify your code by passing the selected options as array in the view.
// Given $selectedOptions = [1, 2, 3, 4...]
#foreach($property->amenities as $amenity)
<label class="checkbox-inline control-label">
<input type="checkbox"
name="amenity[]"
value="{{$amenity->id}}"
#if (in_array($amenity->id, $selectedOptions))
checked="checked"
#endif
>{{ $amenity->name }}
</label>
#endforeach

Why is my form only passing input data from last field within foreach loop to database?

I am trying to update some data in my database from a form with this foreach loop:
$players_ids = $_POST['player_ids'];
foreach($players_ids as $player_id) {
foreach($_POST['goals'] as $goals) {
var_dump($goals);
$updateGoals = \DB::table('stats')->where('id', $player_id)->update(['goals' => $goals]);
}
foreach($_POST['assists'] as $assists) {
var_dump($assists);
$updateAssists = \DB::table('stats')->where('id', $player_id)->update(['assists' => $assists]);
}
foreach($_POST['tackles'] as $tackles) {
var_dump($tackles);
$updateTackles = \DB::table('stats')->where('id', $player_id)->update(['tackles' => $tackles]);
}
}
Here is the form:
#foreach($players as $player)
<tr>
<input type="hidden" name="player_ids[]" value="{{ $player->id }}">
<input type="hidden" name="game_id" value="{{ $game->id }}">
<td>{{ $player->fn }} {{ $player->ln }}</td>
<td><input type="number" value="0" name="goals[]" placeholder="goals"></td>
<td><input type="number" value="0" name="assists[]" placeholder="assists"></td>
<td><input type="number" value="0" name="tackles[]" placeholder="tackles"></td>
</tr>
#endforeach
When I try to submit this data, instead of passing through the individual stats of each player to the database, it only passes through the data of the last player in the foreach loop to every player. So if the final player has 3 goals, everyone will get 3 goals in the database. This is obviously not how I would like this to function.
I know soon after this I will run into an issue with updating the data in my database, because I'm not looking to override what is already in the database, but instead add the value passed through to the value already in the database, so if anyone has any knowledge on that as well would be greatly appreciated.
Your form has multiple copies of elements with the same name. Due to this, it only uses the last element with that name.
To utilize an array of values, you will need to use [] like you did for player_ids.
The reason this is happening is you are updating each player with the very last value set for goals, assists, and tackles. (Actually you are updating each player with every set for goals, assists and tackles, resulting in many queries.) You might need to change up your inputs so you know exactly what to update each player with.
This will also result in less looping and fewer queries.
#foreach($players as $player)
<tr>
<input type="hidden" name="player_ids[]" value="{{ $player->id }}">
<input type="hidden" name="game_id" value="{{ $game->id }}">
<td>{{ $player->fn }} {{ $player->ln }}</td>
<td><input type="number" value="0" name="goals[{{ $player->id }}]" placeholder="goals"></td>
<td><input type="number" value="0" name="assists[{{ $player->id }}]" placeholder="assists"></td>
<td><input type="number" value="0" name="tackles[{{ $player->id }}]" placeholder="tackles"></td>
</tr>
#endforeach
$players_ids = $_POST['player_ids'];
foreach ($players_ids as $player_id) {
$updates = \DB::table('stats')->where('id', $player_id)->update([
'goals' => $_POST['goals'][$player_id],
'assists' => $_POST['assists'][$player_id],
'tackles' => $_POST['tackles'][$player_id]
]);
}
This is untested, but if you want it to be additive in your database and not overwrite past values, you might be able to do something like this...
$players_ids = $_POST['player_ids'];
foreach($players_ids as $player_id) {
$updates = \DB::table('stats')->where('id', $player_id)->update([
'goals' => $_POST['goals'][$player_id] . '+' . DB::raw('goals'),
'assists' => $_POST['assists'][$player_id] . '+' . DB::raw('assists'),
'tackles' => $_POST['tackles'][$player_id] . '+' . DB::raw('tackles')
]);
}
Generally a better route would be to not make them additive though, and then you'd just use sum() to figure out how many goals, tackles, and assists each player has. Then you'd be able to do additional filtering on that like goals by date, goals by game, etc...

Laravel set checkboxes checked based on database value

I am trying to set checkboxes checked based on database value. One user can have have multiple checkbox values.
Checkboxes are generated from database table called child_age_groups:
#foreach ($child_age_groups as $age)
<div class="checkbox checkbox-info checkbox-inline">
<input class="age_group_checkbox" type="checkbox" name="age_group[]" id="age_group{{$age->id}}" "/>
<label for="age_group{{$age->id}}">{{$age->age_group}}</label>
</div>
#endforeach
So in my controller I get all the options that user has like this
$nanny_babysitting_ages = Nanny_babysitting_ages::where('user_id', user()->id)->get();
My nanny_babysitting_ages table is this
user_id | ages
and my child_age_groups table where I populate the checkboxes are this:
id | age_group
How can I set the checkboxes selcted based on the values from database?
This is how I resolved it, I added foreach and if statement in the input to check if it the same value as from database:
<div class="form-group" id="ageCheckboxes">
#foreach ($child_age_groups as $age)
<div class="checkbox checkbox-info checkbox-inline">
<input class="age_group_checkbox" type="checkbox" value="{{$age->id}}" name="age_group[]" id="age_group{{$age->id}}" #foreach ($nanny_babysitting_ages as $ages) #if($age->id == $ages->ages ) checked #endif #endforeach />
<label for="age_group{{$age->id}}">{{$age->age_group}}</label>
</div>
#endforeach
</div>
you can use this "#checked(true)" like :-
<input class="custom-control-input army" type="checkbox" id="customCheckbox1" #checked($emp_plus->army != 0)>

Laravel 5.2 Blade - Undefined offset: 5 in my loop for

i'm creating admin of my articles, in my resource EDIT post i have some problems, i would like show all tags of my post that i'm editing, i'm tryng like this:
I created a variable array with all tags id relation with the post edited:
$post_tags[0]->tag_id // it return some id of tag's post
Now i would show all tag's post like input checked in my form edit.blade.php
#for ($i = 0; $i < count($all_tags); $i++)
#if($all_tags[$i]->id != $post_tags[$i]->tag_id)
<input style="cursor: pointer;" type="checkbox" name="tags[]" id=" {{$all_tags[$i]->slug}}" value="{{$all_tags[$i]->id}}" data-parsley-mincheck="2" class="flat"/>
#else
<input style="cursor: pointer;" type="checkbox" name="tags[]" id="{{$all_tags[$i]->slug}}" value="{{$all_tags[$i]->id}}" data-parsley-mincheck="2" class="flat" checked/>
#endif
#endfor
But i'm getting this error:
ErrorException in Collection.php line 1187: Undefined offset: 5 (View:
C:\xampp\htdocs\sofis\resources\views\admin\post\edit.blade.php)
Larvael 5.3 and above
As others have said, you need to check to make sure the index exists. You can also simplify your logic some by using #foreach instead of #for:
#foreach ($all_tags as $tag)
<input style="cursor: pointer;" type="checkbox" name="tags[]" id=" {{$tag->slug}}" value="{{$tag->id}}" data-parsley-mincheck="2" class="flat" {{ (isset($post_tags[$loop->index]) && $post_tags[$loop->index]->tag_id == $tag->id) ? 'checked' : '' }} />
#endforeach
You could improve Samsquanch's answer to match with versions lesser than 5.3. You can access array index by defining $key in foreach() like shown bellow.
#foreach ($all_tags as $key => $tag)
<input style="cursor: pointer;" type="checkbox" name="tags[]" id=" {{$tag->slug}}" value="{{$tag->id}}" data-parsley-mincheck="2" class="flat" {{ (isset($post_tags[$key]) && $post_tags[$key]->tag_id == $tag->id) ? 'checked' : '' }} />
#endforeach
This means $post_tags[$i] doesn't have element with index = 5. You shouldn't use $array[$index] method if you're not sure element with this index exists. Or you should check it before use:
#if (isset($post_tags[$i]) && $all_tags[$i]->id != $post_tags[$i]->tag_id)
I guess $post_tags does not have index 5, so $post_tags[$i] fails

Categories