I have a project using JS and Laravel.
In blade.php I have a list of items with checkboxes, the list I retrieve from the external database based on its status. I need to be able to select some items and by one click change its status (for example "archive").
function getSelected(){
let selected = new Array()
let tblTickets = document.getElementById('tblTickets')
let checked = tblTickets.getElementsByTagName("input")
for (let i = 0; i < checked.length; i ) {
if (checked[i].checked) {
selected.push(checked[i].value)
}
}
if (selected.length > 0) {
let nr = selected.map(Number)
console.log(nr)
}
}
Here is my JS code which gives me the array of numbers (id(s)- primary keys of selected items)
In web.php I created named route for update:
Route::put("/tickets/update", [TicketsController::class, 'update'])->name('tickets.update');
In ticketsController I have following function:
public function update($ids){
foreach ($ids as $id) {
$tickets = DB::connection('secondDB')->table('ticket')
->join('ticket_status', 'id', '=', 'status_id')
->where('id', '=', $id)
->update(['name' => 'Closed']);
}
$route= route('tickets.update');
return view('tickets', [
'tickets' => $tickets,
'route' => $route
}
(its second connected external database, so I cannot make Model for it, so I white query manually)
In tickets.blade I added script so I can access route variable in JS
<script>
const ticketsApi = @json($route);
</script>
My question is - how to POST an array of ids of checked tickets to the "update" function in Controller using the route I pass in blade.php? (I know I can loop as well in JS, but if I'll have 1000 tickets, I gonna need to POST 1000 requests, I find it more effective to loop in PHP).
this one doesn't work
fetch(route,
{
method: "POST",
body: JSON.stringify(numbers)
})
.then(res => res.json())
.catch(error => {
console.error('Error:', error);
})
.then(data => {
console.log(JSON.stringify(data));
});
Thank you for any hints.
Updated:
js function:
function getSelected(){
let payload = new Array()
let tblTickets = document.getElementById('tblTickets')
let checked = tblTickets.getElementsByTagName("input")
for (let i = 0; i < checked.length; i ) {
if (checked[i].checked) {
payload.push(checked[i].value)
}
}
let numbers = []
if (payload.length > 0) {
numbers = payload.map(Number)
console.log(numbers)
}
const putMethod = {
method : 'PUT',
headers: {
'Content-type': 'application/json; charset=UTF-8'
},
body: JSON.stringify(numbers)
}
fetch(urlUpdate, putMethod)
.then(res => res.json())
.then(data => {
console.log(data);
})
.catch(error => {
console.error('Error:', error);
})
}
web.php:
Route::put("/tickets/update", [TicketsController::class, 'update'])->name('tickets.update');
Controller:
public function update(Request $request): \Illuminate\Http\JsonResponse
{
$request->validate([
'ids' => ['required', 'array', 'min:1'],
'ids.*' => ['integer']
]);
$tickets = DB::connection('secondDb')->table('ticket')
->join('ticket_status', 'id', '=', 'status_id')
->whereIn('id', $request->input('ids'))
->update(['name' => 'Closed ']);
return response()->json([
'ticketsUpdated' => $tickets
]);
}
I still recieve two errors: action.js:57 PUT http://mypath/tickets/update 419 (unknown status) action.js:63 Error: SyntaxError: Unexpected token < in JSON at position 0
I really cannot figure out how to pass my array, split it on numbers as id and update database. I have an build in update route for internal database. But for external I cannot use safe() and build in function provides with an id in route /bills/{id}, but I want to update a bunch of them, not one by one
CodePudding user response:
First you use the POST
method in your fetch request, while your route uses the PUT
verb.
So you have to change the method specified in your fetch to PUT
.
Here are some problems with your controller:
Your id array is in your request body and not as a parameter of the URL, so you need to adapt your controller action to use the Request.
You want to use a route with a list of id's to avoid making 1000 queries to the database, but you are doing exactly this because you are using a foreach and it is not optimized. You can use
whereIn()
instead.Knowing that you are using fetch, prefer to return a JSON response rather than a view.
Here is a code example:
public function update(Request $request)
{
$request->validate([
'ids' => ['required', 'array', 'min:1'],
'ids.*' => ['integer']
]);
$tickets = DB::connection('secondDB')->table('ticket')
->join('ticket_status', 'id', '=', 'status_id')
->whereIn('id', $request->input('ids'))
->update(['name' => 'Closed']);
return response()->json([
'ticketsUpdated' => $tickets;
]);
}
CodePudding user response:
Thx everyone. I found the solution to make it work without JS only Laravel
in blade:
<form action="/tickets/update" method="POST">
@csrf
@method('PUT')
@foreach($tickets as $ticket)
<tr>
<td>
<input class="check" type="checkbox" id="{{$ticket->ticket_id}}" value="{{$ticket->ticket_id}}" name="ids[]" >
</td>
in controller:
public function update(Request $request)
{
$numbers = $request->input('ids');
foreach ($numbers as $number)
{
$tickets = DB::connection('osdtbs')->table('ticket')
->where('ticket_id', '=', $number)
->update(['status_id' => '7']);
}
return redirect('/tickets');
}