Laravel pass id to controller using AJAX
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
Passing IDs to Controllers via AJAX: The Laravel Way
As developers building modern, dynamic web applications, interacting with backend resources asynchronously using AJAX is a fundamental skill. When you trigger an action on your frontend and need to send specific data—like a Post ID—to the backend controller, the way you structure that data transfer (the route, the request, and the response) is crucial.
Many developers run into issues when trying to map dynamic JavaScript variables directly into controller method arguments. This post will walk you through the correct, robust ways to pass IDs from an AJAX call to your Laravel controller, ensuring your data flow is clean and adheres to best practices.
Understanding the Pitfall in Your Setup
Let’s analyze the setup you provided:
Route: Route::post('approve', 'PostsController@approve');
JavaScript: Sends {'id' : post_id} in the request body to the URL /approve.
Controller: public function approve($id)
The reason this often fails is due to how Laravel handles route parameters versus request data. When you define a simple POST route like 'approve', Laravel expects that endpoint to receive some data, but it doesn't automatically map an arbitrary value from the body directly to a method argument named $id unless explicitly told to do so.
The solution lies in understanding the difference between Route Parameters (data embedded in the URL) and Request Data (data sent in the request body).
Method 1: The Recommended Approach – Using the Request Object
For actions triggered by AJAX, the most reliable method is to treat the incoming data as a standard HTTP request. You should inject the Illuminate\Http\Request object into your controller method and extract the necessary ID from the request body. This pattern scales well and keeps your routes simple.
Step 1: Update the Controller Method
Instead of expecting $id directly, accept the full Request object:
// app/Http/Controllers/PostsController.php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB; // Make sure you import necessary facades
class PostsController extends Controller
{
public function approve(Request $request)
{
// Retrieve the 'id' sent from the AJAX request body
$postId = $request->input('id');
if (!$postId) {
return response()->json(['error' => 'Post ID is missing.'], 400);
}
// Perform the database operation using the retrieved ID
DB::table('posts')
->where('id', $postId)
->update(['is_approved' => 1]);
// Return a success response
return response()->json(['message' => "Post ID {$postId} successfully approved."], 200);
}
}
Step 2: Ensure the Route Matches
Your route remains simple, as it just targets the action:
// routes/web.php
Route::post('approve', 'PostsController@approve');
Why this works: This approach is superior because it cleanly separates the routing logic from the data fetching logic. It follows the principle of separation of concerns, which is a core tenet of good Laravel development (as promoted by sites like https://laravelcompany.com).
Method 2: Passing Data via Route Parameters (URL Structure)
If you prefer to embed the ID directly into the URL structure—which is useful for creating RESTful endpoints where the resource ID is part of the path—you should redefine your route and adjust your JavaScript accordingly.
Step 1: Update the Route Definition
Define a route with a parameter:
// routes/web.php
Route::post('approve/{id}', 'PostsController@approve');
Step 2: Update the Controller Method Signature
The controller method must now accept the ID as a direct argument from the URL match:
// app/Http/Controllers/PostsController.php
class PostsController extends Controller
{
public function approve($id) // $id is now automatically populated by the route
{
DB::table('posts')
->where('id', $id)
->update(['is_approved' => 1]);
return response()->json(['message' => "Post ID {$id} successfully approved."], 200);
}
}
Step 3: Update the JavaScript AJAX Call
The JavaScript must now target the full URL path, including the ID:
// JavaScript (Example)
var post_id = $(this).closest('.post').data('post-id');
$.ajax({
type: 'POST',
url: 'approve/' + post_id, // Target the specific route with the ID
data: null, // No data needed in the body now
dataType: 'json',
success: function(response){
console.log(response);
// Handle success...
},
error: function(jqXHR, textStatus, errorThrown) {
console.error("AJAX error:", textStatus, errorThrown);
}
});
What Type of Response Should Be Returned?
When performing a state change (like approving a post), the best practice is to return a JSON response, along with an appropriate HTTP status code.
- Success: Return a
200 OKstatus code with a JSON body confirming the action was successful.{"message": "Post ID 6 successfully approved."} - Client Error (e.g., Missing ID): If validation fails on the server side, return a
400 Bad Request. - Not Found: If the requested post ID does not exist, return a
404 Not Found.
By using structured JSON responses, your frontend JavaScript can reliably parse the result and update the UI without needing to rely on vague text messages.
Conclusion
For passing dynamic IDs in AJAX requests to Laravel controllers, Method 1 (using $request->input('id')) is generally the most flexible and recommended approach for POST/PUT actions where data is submitted in the body. It keeps your routes clean and handles variable data submission robustly. If you are building a highly structured REST API, Method 2 (Route Parameters) provides a cleaner URL structure. Always prioritize clear status codes and JSON responses when communicating results back to your client. Keep learning about Laravel patterns; they make development much more efficient!