You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel实现DataTable表格按年份Ajax筛选的代码问题排查

现有代码错误点排查
  • 筛选下拉逻辑错误:下拉选项遍历全量业务数据生成,option值绑定数据ID、显示完整日期字段,既没有提取去重的独立年份列表,传递的ID参数也无法用于年份匹配
  • DataTable渲染模式冲突:开启Ajax配置时没有移除Blade中写死的静态<tbody>内容,Ajax模式下DataTable会完全接管表格内容渲染,静态行和Ajax返回内容混杂会直接导致排版错乱、重复行
  • 请求逻辑缺失:注释代码中的筛选参数仅在页面初始化时取值一次,不会跟随下拉选择更新;Laravel默认POST请求需要校验CSRF令牌,未携带令牌会直接返回419错误
  • 列配置缺失:开启Ajax模式时未配置columns参数指定每列对应的数据字段,DataTable无法正确匹配渲染内容
  • 事件绑定失效:删除按钮的点击事件仅在页面初始加载时绑定,Ajax重载生成的新行不会绑定事件,点击无响应

可行实现方案

方案一:修复现有Ajax+DataTable无刷新筛选(支持大数据量)

注意:使用该方案需要先安装DataTable官方Laravel扩展包,执行命令composer require yajra/laravel-datatables-oracle即可。

  1. Blade模板修正
    首先在页面<head>区域加入CSRF标签:
    <meta name="csrf-token" content="{{ csrf_token() }}">
    
    替换筛选下拉框的生成逻辑,使用去重的年份列表作为选项:
    <div class="col-md-2">
        <select id="filter-tahun" class="form-control filter">
            <option value="">Pilih Tahun</option>
            @foreach ($years as $year)
            <option value="{{$year}}">{{$year}}</option>
            @endforeach
        </select>
    </div>
    
    清空表格静态<tbody>内容,Ajax模式下由DataTable自动渲染行:
    <table id="tabelpekerjaan" class="table table-bordered">
        <thead>
            <tr>
                <th style="width: 10px">No.</th>
                <th>Paket Pekerjaan</th>
                <th>Tanggal</th>
                <th>Nama Perusahaan</th>
                <th>Lokasi Pekerjaan</th>
                <th>PPK</th>
                <th>HPS</th>
                <th>Gambar</th>
                <th style="width: 120px">Aksi</th>
            </tr>
        </thead>
        <tbody></tbody>
    </table>
    
  2. 后端逻辑修正
    新增Ajax接口路由:
    // routes/web.php
    Route::post('/datapekerjaan', [PekerjaanController::class, 'dataPekerjaan']);
    
    控制器中新增接口方法,处理筛选、返回DataTable要求的JSON格式数据:
    // app/Http/Controllers/PekerjaanController.php
    public function dataPekerjaan(Request $request)
    {
        $data = Pekerjaan::with(['penyedia', 'user'])
            ->when($request->tahun, function($query) use ($request) {
                // 按年份匹配日期字段
                $query->whereYear('tanggal', $request->tahun);
            })
            ->get();
    
        return datatables()->of($data)
            ->addIndexColumn() // 自动生成序号列
            ->editColumn('hps', function($row) {
                return 'Rp. '.number_format($row->hps,0,',',',');
            })
            ->editColumn('gambar', function($row) {
                return '<img src="'.asset('gambarpekerjaan/'.$row->gambar).'" style="width: 100px" alt="">';
            })
            ->addColumn('aksi', function($row) {
                $btn = '<a href="/editpekerjaan/'.$row->id.'" type="button" class="btn btn-outline-primary">Edit</a>';
                if (auth()->user()->status == 'super') {
                    $btn .= '<a href="#" type="button" class="btn btn-outline-danger delete" data-id="'.$row->id.'" data-nama="'.$row->pekerjaan.'">Hapus</a>';
                }
                return $btn;
            })
            ->rawColumns(['gambar', 'aksi']) // 声明HTML列不转义
            ->make(true);
    }
    
    原页面渲染方法中传递去重的年份列表:
    public function index()
    {
        $years = Pekerjaan::selectRaw('YEAR(tanggal) as year')->distinct()->pluck('year');
        return view('对应视图路径', compact('years'));
    }
    
  3. 前端脚本修正
    替换原DataTable初始化逻辑,补全参数配置、事件委托:
    <script>
    $(function () {
        // 全局自动携带CSRF令牌
        $.ajaxSetup({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            }
        });
    
        const table = $('#tabelpekerjaan').DataTable({
            "paging": true,
            "lengthChange": true,
            "searching": true,
            "ordering": true,
            "info": true,
            "autoWidth": true,
            "responsive": true,
            "processing": true,
            "serverSide": true,
            "ajax":{
                url: "{{url('/datapekerjaan')}}",
                type:"POST",
                data:function(d){
                    d.tahun = $("#filter-tahun").val(); // 实时读取选中的年份
                }
            },
            "columns": [
                {"data": "DT_RowIndex", "orderable": false, "searchable": false},
                {"data": "pekerjaan"},
                {"data": "tanggal"},
                {"data": "penyedia.nama"},
                {"data": "lokasi"},
                {"data": "user.name"},
                {"data": "hps"},
                {"data": "gambar"},
                {"data": "aksi", "orderable": false, "searchable": false}
            ]
        });
    
        // 选择年份后重载表格
        $(".filter").on('change',function(){
            table.ajax.reload(null,false);
        })
    
        // 用事件委托绑定删除事件,兼容Ajax生成的新元素
        $(document).on('click', '.delete', function(){
            var idpekerjaan = $(this).attr('data-id');
            var namapekerjaan = $(this).attr('data-nama');
    
            Swal.fire({
                title: 'Apakah Anda yakin?',
                text: "Paket Pekerjaan "+namapekerjaan+" akan dihapus!",
                icon: 'warning',
                showCancelButton: true,
                confirmButtonColor: '#3085d6',
                cancelButtonColor: '#d33',
                confirmButtonText: 'Ya, yakin!'
            }).then((result) => {
                if (result.isConfirmed) {
                    window.location = "/deletepekerjaan/"+idpekerjaan
                    Swal.fire(
                        'Dihapus!',
                        'Data berhasil dihapus.',
                        'success'
                    )
                }
            });
        });
    
        $('.select2bs4').select2({
            theme: 'bootstrap4'
        })
    });
    
    @if (session()->has('message'))
        toastr.success("{{session()->get('message')}}")  
    @endif
    </script>
    

方案二:轻量表单筛选(代码改动最小,适合千条以内数据量)

不需要写Ajax接口,直接用GET传参实现筛选,保留原有静态表格渲染逻辑:

  1. 把筛选下拉框包裹在表单中,选中后自动提交:
    <form method="get">
        <div class="col-md-2">
            <select id="filter-tahun" name="tahun" class="form-control filter" onchange="this.form.submit()">
                <option value="">Pilih Tahun</option>
                @foreach ($years as $year)
                <option value="{{$year}}" {{request('tahun') == $year ? 'selected' : ''}}>{{$year}}</option>
                @endforeach
            </select>
        </div>
    </form>
    
  2. 原页面渲染方法中加入筛选逻辑即可:
    public function index(Request $request)
    {
        $years = Pekerjaan::selectRaw('YEAR(tanggal) as year')->distinct()->pluck('year');
        $pekerjaan = Pekerjaan::with(['penyedia', 'user'])
            ->when($request->tahun, function($query) use ($request) {
                $query->whereYear('tanggal', $request->tahun);
            })
            ->get();
        return view('对应视图路径', compact('pekerjaan', 'years'));
    }
    

该方案选中选项后页面会自动刷新,展示匹配年份的数据,无需额外编写JS逻辑,出错概率极低。


内容的提问来源于stack exchange,提问作者YuPi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 14:54:19