Update pivot table in Laravel - laravel

I am trying to update a table with spots. I wanted to do it on click with livewire but nothing worked so I figured it would be easier to just use the methods in the Laravel controller that I already had. The attach and detach are used because I have two tables in my view, one with all the stations and the other one, the one I am trying to update, with the stations that are already in a workbook. With the way I have my method right now I can update everything except for the spot and I am not sure why. It is a many to many relationship between the workbooks and stations and spots are an extra field in the pivot table.
<form action="{{route('admin.workbooks.update', [$client_id, $workbook_id])}}" method="POST" enctype="multipart/form-data">
#csrf
#method('PUT')
<div class="form-group">
<label for="">Media Schedule Name</label>
<input type="text" class="form-control" name="wrkb_name" value="{{$workbook_name}}">
</div>
<table class="table-auto w-full mb-6">
<thead>
<tr>
<th class="px-4 py-2"></th>
#if($showLetter)
<th wire:click="sortBy('call_letter')" style="cursor: pointer;" class="px-4 py-2">Call Letter #include('partials.sort-icon',['field'=>'call_letter'])</th>
#endif
<th style="cursor: pointer;" class="px-4 py-2">Spots #include('partials.sort-icon',['field'=>'spots'])</th>
</tr>
</thead>
<tbody>
#foreach($selected_stations as $key => $selected_station)
<tr>
<td class="border px-4 py-2">
<input name="selected_stations[]" wire:model="selected_already" value="{{ $selected_station->id }}" type="checkbox">
</td>
#if($showLetter)
<td class="border px-4 py-2">{{$selected_station->call_letter}}</td>
#endif
<td class="border px-4 py-2">
<input name="spot" type="text" class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500" value="{{$selected_station->pivot->spot}}" placeholder="{{$selected_station->pivot->spot}}"></td>
<td>
</td>
</tr>
#endforeach
</tbody>
</table>
<br>
<table class="table-auto w-full mb-6">
<thead>
<tr>
<th class="px-4 py-2"></th>
#if($showLetter)
<th wire:click="sortBy('call_letter')" style="cursor: pointer;" class="px-4 py-2">Call Letter #include('partials.sort-icon',['field'=>'call_letter'])</th>
#endif
</tr>
</thead>
<tbody>
#foreach($stations as $key => $station)
<tr>
<td class="border px-4 py-2">
<input name="stations[]" wire:model="selected" value="{{ $station->id }}" type="checkbox">
</td>
#if($showLetter)
<td class="border px-4 py-2">{{$station->call_letter}}</td>
#endif
<td>
</td>
</tr>
#endforeach
</tbody>
</table>
#else
<p class="text-center">Whoops! No users were found 🙁</p>
#endif
<div class="w-full flex pb-10" >
<div class="w-1/6 relative mx-1 space-x-6">
<button class="block appearance-none w-full bg-black border border-gray-200 text-white py-3 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500">Edit Media Schedule</button>
</div>
</div>
</form>
public function update(UpdateWorkbookRequest $request,Client $client, Workbook $workbook)
{
$workbook->update($request->only('wrkb_name'));
$workbook->stations()->detach($request->input('selected_stations', []));
$workbook->stations()->attach($request->input('stations', []));
$workbook->stations()->updateExistingPivot('spot', []);
return redirect()->route('admin.workbooks.edit', [$client->id, $workbook->id])->with('success', 'Successfully Edited the Workbook');
}
This is how one of the relationship looks like, although I don't think this helps much
public function workbooks()
{
return $this->belongsToMany(\App\Models\Workbook::class, 'station_workbook', 'station_id', 'workbook_id')->withPivot('spot')->withTimestamps();;
}
I also found that I could use something like this, but I only want to update that specific record and from this code it seems like it updates every instance of that station, no matter what workbook and it doesn't work anyway.
foreach($workbook->stations as $key => $station){
dd($station->workbooks);
$station->workbooks()->updateExistingPivot($key, ['spot' => $request ->spot]);
}
I have also tried this with no success
$usedStations=$request->input('stations', []);
$workbook->update($request->only('wrkb_name'));
$workbook->stations()->detach($request->input('selected_stations', []));
$workbook->stations()->attach($request->input('stations', []));
foreach($usedStations as $usedStation)
{
$station_id = Station::where('id',$usedStation)->value('id');
$workbook->stations()->updateExistingPivot($station_id, ['spot' => $request ->spot]);
}

Quoting from Laravel Doc: (Link)
When attaching a relationship to a model, you may also pass an array
of additional data to be inserted into the intermediate table
So, you can do :
$workbook->stations()->attach($request->input('stations', []),['spot'=>$request->input('spot')]);
UPDATE
Currently, in your code only single value for 'spot' field is being passed to the request. Change it to:
<input name="spot[{{$selected_station->id}}]" type="text" class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500" value="{{$selected_station->pivot->spot}}" placeholder="{{$selected_station->pivot->spot}}"></td>
update() method should be:
public function update(UpdateWorkbookRequest $request,Client $client, Workbook $workbook)
{
$workbook->update($request->only('wrkb_name'));
$workbook->stations()->detach($request->input('selected_stations', []));
$workbook->stations()->attach($request->input('stations', []));
//take only the spot values of selected_stations that were unchecked
$spots = array_diff_key($request->input('spot',[]), array_flip($request->input('selected_stations',[])));
foreach($spots as $station_id=>$spot_value){
$workbook->stations()->updateExistingPivot($station_id, ['spot'=>$spot_value]);
}
return redirect()->route('admin.workbooks.edit', [$client->id, $workbook->id])->with('success', 'Successfully Edited the Workbook');
}

Related

Attempt to read property "id" on bool [duplicate]

I keep encountering this error on Laravel 8 with PHP 8. Im grabbing the id from the view like so:
<button type="submit">
Payslip
</button>
This then goes to web.php like so:
Route::get('employees/{id}/payslip', ['App\Http\Controllers\PrintController', 'print'])->name('employees.payslip');
It then goes to the print function like so:
public function print($id)
{
$employees = Employees::findOrFail($id);
$teams = Team::all();
return view('employees.payslip',compact('employees', 'teams'));
}
When i remove the return view line and replace it with:
dd($employees);
It gives me the correct information but when i keep the line:
return view('employees.payslip',compact('employees', 'teams'));
and send it the view 'employees.payslip': it gives me the error: anyone has any ideas?
#forelse($employees as $employee)
<tr>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{{$employee->name}}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{{$employee->surname}}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{{$employee->address}}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{{$employee->phone}}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{{$employee->role}}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{{$employee->absent}}
</td>
</tr>
#empty
<td>
No Information to Display
</td>
#endforelse
Since you are fetching one record from Employee model.So it return single object.
$employees = Employees::findOrFail($id);
so as #aynber said , you dont need loop.Its just like below to access data
{{$employees->name}}
If you loop then error says
Attempt to read property “name” on bool laravel 8, variable not
transfering to view
#forelse($employees as $employee)
#php
dd($employee);
#endphp
#empty
<td>
No Information to Display
</td>
#endforelse
here dd($employee); will return true so it throwing erorr
Also keep in mind if no record then it might return null so make sure to chek like isset or $employees->name??null

Trying to check if a database cell contains a certain string then change the badge color

So Iam using vuex and laravel for this project and i have had some difficulties with trying to change the badge depending on the displayed data in my dashboard. Currently my dashboard looks like this:
Now what i would like to happen is when an Error Message contains for instance the string 99012. That the badge color according to the Error message code. I havent been able to make the {"Result":[{"ERRORS":"99012: Weborder number already exists : 20211049"}]} in JSON format that is why its been displayed like this.
Currently my Controller looks like this:
class GencomController extends Controller
{
/**
* Display a listing of the resource.
*
*
*/
public function index(Request $request)
{
//
// $log = Log::get('RESPONSE');
// Get all the Response rows from database.
$data = Log::all();
// Convert data into json array
//$decoded = json_encode($data, true);
$decoded = json_decode($data);
return ($decoded);
}
This is how my store.js looks:
api_logs: {
loading: false,
data: [],
},
and here is my .vue component:
<div class="mt-8 flex flex-col">
<div class="-my-2 -mx-4 overflow-x-auto sm:-mx-6 lg:-mx-8">
<div class="inline-block py-2 align-middle">
<div class="overflow-auto relative shadow-sm ring-1 ring-black ring-opacity-5">
<table class="table-fixed divide-y divide-gray-300">
<thead class="bg-gray-50">
<tr>
<th scope="col" class="w-1/15 py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6 lg:pl-8">ID</th>
<th scope="col" class="w-1/13 px-3 py-3.5 text-left text-sm font-semibold text-gray-900">Date & Time</th>
<th scope="col" class=" px-3 py-3.5 text-left text-sm font-semibold text-gray-900">Error Message</th>
<th scope="col" class=" px-3 py-3.5 text-left text-sm font-semibold text-gray-900">Status Badge</th>
<th scope="col" class=" px-3 py-3.5 text-left text-sm font-semibold text-gray-900">Edit</th>
<th scope="col" class=" relative py-3.5 pl-3 pr-4 sm:pr-6 lg:pr-8">
<span class="sr-only">Edit</span>
</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 bg-white">
<tr v-for="log in logs" :key="log.APIGROUPNO">
<td class="w-1/15 py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6 lg:pl-8">{{ log.APIGROUPNO }}</td>
<td class=" px-3 py-4 text-sm text-gray-500">{{ log.DATETIMEEXECUTED }}</td>
<!-- <td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ log.JSONBDY }}</td>-->
<td class="break-all px-3 py-4 text-sm text-gray-500">{{ log.RESPONSE }}</td>
<td class="break-all px-3 py-4 text-sm text-gray-500"><span class="bg-red-100 text-red-800 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded dark:bg-red-200 dark:text-red-900">Error</span></td>
<td class="relative py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 lg:pr-8">
<a href="#" class="text-indigo-600 hover:text-indigo-900"
>Edit<span class="sr-only">, {{ log.APIGROUPNO }}</span></a
>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
And here is my Model:
class Log extends Model
{
use HasFactory;
protected $connection = 'gencom';
protected $table = 'GMAPILOG';
protected $primaryKey = 'APIGROUPNO';
public $timestamps = false;
protected $casts = ["Result"=>'array'];
protected $fillable = [
'APIGROUPNO',
'DATETIMEEXECUTED',
'PACKAGENAME',
'TOKEN',
'APINAME',
'PARAMETERLIST',
'JSONBDY',
'RESPONSE'
];
}
The json response i get returned from the db:
RESPONSE: "{\"Result\":[{\"ERRORS\":\"99012: Weborder number already exists : 20211049\"}]}"
So to make a quick summary, i would like the badge color to change according to the code gotten in the message. I have tried it for a while but i cant seem to figure it out as i do struggle a bit with vuex. I hope some could explain me their thought process.
Thanks in advance.

Getting stored Json query from database and extracting only the values i want

Currently iam working on a dashboard where i have to get stored JSON query's from the database and then select only select the keys i want to use. Iam working with laravel and Vuex.
Currently my controller looks like this.
public function index()
{
//
$log = Log::all();
return (json_encode($log));
}
At the moment this returns the table that i want and I'am able to select the column i want.
This is how my HTML looks
<tr v-for="log in logs" :key="log.APIGROUPNO">
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6 lg:pl-8">{{ log.APIGROUPNO }}</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ log.DATETIMEEXECUTED }}</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ log.JSONBDY }}</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ log.RESPONSE }}</td>
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 lg:pr-8">
<a href="#" class="text-indigo-600 hover:text-indigo-900"
>Edit<span class="sr-only">, {{ log.APIGROUPNO }}</span></a
>
</td>
</tr>
The following code gives me this result.
What i would like to get back is the following:
How would i be able to fix this, i have searched far and wide on the internet but cant seem to find a fitting solution. Any help and/or suggestions would be greatly appreciated.

Trix editor doesn't show up when used inside a #if condition

In larave8 livewire I want to use the trix editor to create an bladeview on the livewire component InfoletterCrud is the following
<div class="container ml-auto mr-auto p-10 min-h-screen">
<div class="page-title ">{{ $page_title }}</div>
<div class="button-line flex flex-col">
#if ($isEditMode)
#if ($showMode)
#include('livewire.show-infoletter')
#else
#include('livewire.create-infoletter')
#endif
#else
<div>
<button wire:click="create()" class="button-cancel text-white font-bold py-2 px-4 rounded my-3">Ajouter une info-lettre</button>
</div>
#if (count($infoletters) > 0)
<table class="w-full table-fixed admin-stripped-table">
<thead>
<tr class="w-full">
<th class="w-1/12">Id</th>
<th class="w-10/12">Titre</th>
<th class="w-1/12">Actions</th>
</tr>
</thead>
<tbody>
#foreach ($infoletters as $infoletter)
<tr>
<td>{{ $infoletter->id }}</td>
<td>{{ $infoletter->title }}</td>
<td>
<div style="display:flex">
<button
wire:click="show({{ $infoletter->id }})"
class="fontawesome-icon">
<span data-toggle="tooltip" title="Voir" class="fa fa-paper-plane fa-xs "></span>
</button>
<button
wire:click="edit({{ $infoletter->id }})"
class="fontawesome-icon">
<span data-toggle="tooltip" title="Modifier" class="fa fa-edit fa-xs "></span>
</button>
<button
wire:click="$emit('openModal', 'livewire-modal', {{ json_encode(['type' => 'L\'infolettre', 'ident' => $infoletter->id]) }})"
class="fontawesome-icon">
<span data-toggle="tooltip" title="Supprimer" class=" fa fa-trash fa-xs "></span>
</button>
</div>
</td>
</tr>
#endforeach
</tbody>
</table>,
#else
<p>Il n'y a aucune info-lettre</p>
#endif
#endif
</div>
</div>
When I place the trix component with #livewire('trix') just above the #if (isEditMode) test, it shows up. But it is not what I want because I am not in the Edit mode.
If I place it in the livewire.create-infoletter include, it doesn't show up.
Even when I place it just after the #if (isEditMode) test, it doesn't show up.
What is the trouble
You don't show your component and how you're initializing Trix, so this is just a guess. I'm assuming you're doing it with Alpinejs, and that Alpine has already made its DOM updates by the time the #if condition executes. Try calling your initialization function using $nextTick - see here: https://alpinejs.dev/magics/nextTick.

Laravel foreach in if statement

This is my code
#if ($story)
<table class="table-auto my-3 w-full">
<thead class="justify-between">
<tr class="bg-gray-800">
<th class="px-16 py-2">
<span class="text-gray-300">#Id</span>
</th>
<th class="px-16 py-2">
<span class="text-gray-300">Name</span>
</th>
<th class="px-16 py-2">
<span class="text-gray-300">Description</span>
</th>
<th class="px-16 py-2">
<span class="text-gray-300">Actions</span>
</th>
</tr>
</thead>
<tbody class="bg-gray-200">
#foreach ($story as $item)
<tr class="bg-white border-4 border-gray-200">
<td class="px-16 py-2 flex flex-row items-center">
{{ $item->id }}
</td>
<td>
{{ Str::words($item->name, 3, $end = '...') }}
</td>
<td class="px-16 py-2">
{!! Str::words($item->description, 6, $end = '...') !!}
</td>
<td class="px-16 py-2">
<a href="{{ route('dashboard.story.edit', $item->id) }}">
<button class="bg-blue-500 text-white px-4 py-1 border rounded-md hover:bg-white hover:border-blue-500 hover:text-black">
Edit
</button>
</a>
</td>
</tr>
#endforeach
</tbody>
</table>
#else
<p>No results found</p>
#endif
This is my controller
public function index()
{
$story = Story::paginate(10);
return view('admin.story.index', ['story' => $story]);
}
I'm using Laravel 8 and I don't want to show table headers when the value is null. Laravel showing tables headers and not showing the 'No results found' message.
Any help would be appreciated.
when you use paginate, your data split. so if you want check this data empty or not just use
#if( $story->total() )
just replace it with
#if ( $story )

Resources