非同期処理で検索をした後、IDが取得されません
解決したいこと
index.blade.phpの絞り込みボタンを押下した後、
表示されるレコードのidを取得したいです
laravel9
composer
MacOS
Ajax
JQuery
LaravelでAjaxとJQueryを利用し、非同期処理を行っております。
非同期で検索処理を行い該当のレコードを表示することはできております。
しかし取得したレコードの詳細、編集画面へ移動することができません
「詳細表示ボタン」「編集ボタン」を押下すると下記のエラーがブラウザにて確認されます・・・
発生している問題・エラー
GET http://localhost:8888/products/undefined 404 (Not Found)
Chromeの検証で上記が確認されているため、
該当のidを取得すればいいと思うのですが、うまく取得ができていない状況です。
該当するソースコード
$(function() {
$('#search-form').submit(function(event) {
event.preventDefault();
var csrfToken = $('meta[name="csrf-token"]').attr('content');
$.ajax({
url: "http://localhost:8888/product/public/products/search",
type: 'GET',
dataType: "json",
data: {
search: $('#search').val(),
company_id: $('#company').val(),
priceMin: $('input[name="price_min"]').val(),
priceMax: $('input[name="price_max"]').val(),
stockMin: $('input[name="stock_min"]').val(),
stockMax: $('input[name="stock_max"]').val(),
}
}).done((response) => {
console.log(response);
var $result = $('#search-results');
$result.empty();
$.each(response.products, function(index, product){
var productId = product.id;
var html = `
<tr>
<td>${product.product_name}</td>
<td>${product.company_name}</td>
<td>${product.price}</td>
<td>${product.stock}</td>
<td>${product.comment}</td>
<td><img src="${product.img_path}" alt="商品画像" width="100"></td>
<td>
<a href="/products/${productId}" class="btn btn-info btn-sm mx-1">詳細表示</a>
<a href="/products/${productId}/edit" class="btn btn-primary btn-sm mx-1">編集</a>
<form method="POST" action="/products/${productId}" class="d-inline">
<input type="hidden" name="_token" value="${csrfToken}">
<input type="hidden" name="_method" value="DELETE">
<button type="submit" class="btn btn-danger btn-sm mx-1">削除</button>
</form>
</td>
</tr>`;
$result.append(html);
});
}).fail((error) => {
console.log('AJAXが失敗しました');
});
});
});
class ProductController extends Controller
{
public function index(Request $request){
$products = Product::search($request->search, $request->company_id, $request->price_min, $request->price_max, $request->stock_min, $request->stock_max)
->paginate(10);
$company_lists = Company::pluck('company_name', 'id');
$company = $request->company_id;
return view('products.index', compact('products', 'company_lists', 'company'));
}
public function search(Request $request)
{
$products = Product::search($request->search, $request->company_id, $request->price_min, $request->price_max, $request->stock_min, $request->stock_max)
->paginate(10);
$company_lists = Company::pluck('company_name', 'id');
$company_id = $request->company_id;
$products = $products->map(function ($product) {
return [
'product_name' => $product->product_name ?? '',
'company_name' => $product->company->company_name ?? '',
'price' => $product->price ?? '',
'stock' => $product->stock ?? '',
'comment' => $product->comment ?? '',
'img_path' => asset($product->img_path) ?? '',
];
});
return response()->json([
'products' => $products,
'company_id' => $company_id,
'company_lists' => $company_lists
]);
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
class Product extends Model
{
use HasFactory;
protected $fillable = [
'id',
'product_name',
'price',
'stock',
'company_id',
'comment',
'img_path',
];
public function sales()
{
return $this->hasMany(Sale::class);
}
public function company()
{
return $this->belongsTo(Company::class);
}
public function getCompany()
{
return $this->company;
}
public static function createProduct($requestData){
$product = new Product();
$product->product_name = $requestData['product_name'];
$product->company_id = $requestData['company_id'];
$product->price = $requestData['price'];
$product->stock = $requestData['stock'];
$product->comment = $requestData['comment'];
// idフィールドは自動インクリメントなので、明示的に設定する必要はありません。
if (isset($requestData['img_path'])) {
$img_path = $requestData['img_path']->store('products', 'public');
$product->img_path = 'storage/' . $img_path;
}
$product->save();
return $product;
}
public function scopeSearch($query, $search, $company, $priceMin, $priceMax, $stockMin, $stockMax)
{
if ($search) {
$query->where('product_name', 'LIKE', "%{$search}%");
}
if ($company) {
$query->whereHas('company', function ($query) use ($company) {
$query->where('company_id', $company);
});
}
if ($priceMin) {
$query->where('price', '>=', $priceMin);
}
if ($priceMax) {
$query->where('price', '<=', $priceMax);
}
if ($stockMin) {
$query->where('stock', '>=', $stockMin);
}
if ($stockMax) {
$query->where('stock', '<=', $stockMax);
}
return $query;
}
}
@extends('layouts.app')
@section('content')
<div class="container">
<h1 class="mb-4">商品情報一覧</h1>
<a href="{{ route('products.create') }}" class="btn btn-primary mb-3">商品新規登録</a>
<div class="search mt-5">
<h2>検索条件で絞り込み</h2>
<form action="{{ route('products.index') }}" method="GET" class="row g-3" id="search-form">
<div class="col-sm-12 col-md-3">
<input type="text" name="search" class="form-control" placeholder="商品名" value="{{ request('search') }}" id="search">
</div>
<div class="col-sm-12 col-md-3">
<select name="company_id" class="form-control" id="company">
<option value="">全て</option>
@foreach($company_lists as $key => $value)
<option value="{{ $key }}" @if($company == $key) selected="selected" @endif>{{ $value }}</option>
@endforeach
</select>
</div>
<div class="col-sm-12 col-md-3">
<input type="number" name="price_min" class="form-control" placeholder="価格の下限" value="{{ request('price_min') }}">
</div>
<div class="col-sm-12 col-md-3">
<input type="number" name="price_max" class="form-control" placeholder="価格の上限" value="{{ request('price_max') }}">
</div>
<div class="col-sm-12 col-md-3">
<input type="number" name="stock_min" class="form-control" placeholder="在庫数の下限" value="{{ request('stock_min') }}">
</div>
<div class="col-sm-12 col-md-3">
<input type="number" name="stock_max" class="form-control" placeholder="在庫数の上限" value="{{ request('stock_max') }}">
</div>
<div class="col-sm-12 col-md-1">
<button class="btn btn-outline-secondary" type="submit">絞り込み</button>
</div>
</form>
</div>
<a href="{{ route('products.index') }}" class="btn btn-success mt-3">検索条件を元に戻す</a>
<div class="products mt-5" >
<h2>商品情報</h2>
<table class="table table-striped" >
<thead>
<tr>
<th>商品名</th>
<th>メーカー</th>
<th>価格</th>
<th>在庫数</th>
<th>コメント</th>
<th>商品画像</th>
<th>操作</th>
</tr>
</thead>
<tbody id="search-results">
@foreach ($products as $product)
<tr>
<td>{{ $product->product_name }}</td>
<td>{{ $product->company->company_name }}</td>
<td>{{ $product->price }}</td>
<td>{{ $product->stock }}</td>
<td>{{ $product->comment }}</td>
<td><img src="{{ asset($product->img_path) }}" alt="商品画像" width="100"></td>
</td>
<td>
<a href="{{ route('products.show', $product->id) }}" class="btn btn-info btn-sm mx-1">詳細表示</a>
<a href="{{ route('products.edit', $product->id) }}" class="btn btn-primary btn-sm mx-1">編集</a>
<form method="POST" action="{{ route('products.destroy', $product->id) }}" class="d-inline">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger btn-sm mx-1">削除</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
{{ $products->appends(request()->query())->links() }}
</div>
@endsection
何卒、ご教授いただけますと幸いです。
よろしくお願い申し上げます