phplaraveldatatableslaravel-datatables

Laravel datatables pass two instance in one view


I am attempting to send two instances of DataTables to my view. The scenario involves having a tab menu with each tab containing a corresponding table. Here is the approach I have taken.

My controller

    public function show(AuthorityPage $authorityPage, 
        AuthorityPageGuideContentDataTable $authorityPageGuideContentDataTable, 
        AuthorityPageAccordionDataTable $authorityPageAccordionDataTable
        )
    {
       
        $blogPosts = BlogPost::where('domain_id', getCurrentDomain())->where('is_active',true)
        ->select(['id','name'])->get();
        $tours = Tour::where('domain_id', getCurrentDomain())
            ->with('generalDetail')->get();
        $destinations = Destination::where('domain_id', getCurrentDomain())
            ->select(['id','name'])->get();
        $keywordIntents = [
            'i' => 'Informational',
            'n' => 'Navigational',
            't' => 'Transactional',
            'c' => 'Commercial',
        ];

$accordionDt = $authorityPageAccordionDataTable->with([
            'authorityPage' => $authorityPage
        ])->html();
$authorityContentDt = $authorityPageGuideContentDataTable->with([
            'authorityPage' => $authorityPage
        ])->html();

return view('pages.authority-pages.show', compact(
            'authorityPage', 
            'blogPosts', 
            'tours', 
            'destinations', 
            'keywordIntents', 
            'authorityContentDt', // first dt
            'accordionDt' //2nd dt
        ));

in my first tab view i render the datatable by

    <div class="card-body py-4">
        <div class="table-responsive">
            {{ $authorityContentDt->table()}}
        </div>
    </div>

in my second tab

  <div class="card-body py-4">
            <div class="table-responsive">
                {{ $accordionDt->table() }}
            </div>
        </div>

one of my datatable class (similar to all of my datatable classes)

class AuthorityPageGuideContentDataTable extends DataTable
{
    public function dataTable(QueryBuilder $query): EloquentDataTable
    {
        return (new EloquentDataTable($query))
        ->editColumn('guide_type', function (DestinationGuideDetails $destinationGuideDetails) {
            return DestinationGuideType::byValue($destinationGuideDetails->guide_type)->name;
        })
        ->editColumn('content', function (DestinationGuideDetails $destinationGuideDetails) {
            return strip_tags($destinationGuideDetails->content);
        })
        ->addColumn('action', function (DestinationGuideDetails $destinationGuideDetails) {
            return '<button class="btn btn-icon btn-active-light-primary w-30px h-30px" onclick="deletedestinationGuideContent('.$this->authorityPage->id.' , '.$destinationGuideDetails->id.')"> '.getIcon("trash","fs-3").'</button>
            <button data-bs-toggle="modal" data-bs-target="#kt_modal_1" class="btn btn-icon btn-active-light-primary w-30px h-30px" onclick="getContent('.$this->authorityPage->id.','.$destinationGuideDetails->id.')"> '.getIcon("notepad-edit","fs-3").'</button>';
        })
        ->rawColumns(['action'])
        ->setRowId(function ($destinationGuideDetails) {
            return "destination-guide-details-{$destinationGuideDetails->id}";
        });
    }

    public function query(DestinationGuideDetails $model): QueryBuilder
    {
        $query = $model->newQuery()
        ->join('destination_guides', 'destination_guide_details.destination_guide_id', '=', 'destination_guides.id')
        ->where('destination_guides.guideable_id', $this->authorityPage->id)
        ->where('destination_guides.guideable_type', 'App\Models\AuthorityPage')
        ->select('destination_guide_details.*');
        return $query;
    }

    public function html(): HtmlBuilder
    {
        return $this->builder()
        ->setTableId('destination-guide-table')
        ->columns($this->getColumns())
        ->minifiedAjax()
        ->dom('rt' . "<'row'<'col-sm-12 col-md-5'l><'col-sm-12 col-md-7'p>>",)
        ->addTableClass('table align-middle table-row-dashed fs-6 gy-5 dataTable no-footer text-gray-600 fw-semibold')
        ->setTableHeadClass('text-start text-muted fw-bold fs-7 text-uppercase gs-0');
    }


    public function getColumns(): array
    {
        return [
            Column::make('guide_type')->name('guide_type'),
            Column::make('content')->name('Content'),
            Column::make('action')->name('Action')->width('10%'),
        ];
    }

    protected function filename(): string
    {
        return 'AuthorityPageGuideContent_' . date('YmdHis');
    }
}

The problem is it returns an alert saying

DataTables warning: table id=destination-guide-table - Invalid JSON response. 
For more information about this error, please see http://datatables.net/tn/1

Solution

  • Firstly, set up routes that invoke your DataTable classes:

    Route::get('/authority-pages/{authorityPage}/destination-guide', [AuthorityPageController::class, 'getAuthorityPageGuideContentData'])->name('authority-pages-get-destination-guide-content');
    Route::get('/authority-pages/{authorityPage}/accordions', [AuthorityPageController::class, 'getAuthorityPageAccordionData'])->name('authority-pages-get-accordions');
    

    In your controller, ensure the methods look like this:

    public function getAuthorityPageAccordionData(AuthorityPage $authorityPage, AuthorityPageAccordionDataTable $authorityPageAccordionDataTable)
    {
        return $authorityPageAccordionDataTable->with([
            'authorityPage' => $authorityPage
        ])->render('pages.authority-pages.show');
    }
    
    public function getAuthorityPageGuideContentData(AuthorityPage $authorityPage, AuthorityPageGuideContentDataTable $authorityPageGuideContentDataTable)
    {
        return $authorityPageGuideContentDataTable->with([
            'authorityPage' => $authorityPage
        ])->render('pages.authority-pages.show');
    }
    

    Now, in your show method, call the html() method from the DataTable instance. You can use the resulting variables in your view like this:

    $accordionDt = $authorityPageAccordionDataTable->with([
        'authorityPage' => $authorityPage
    ])->html();
    
    $authorityContentDt = $authorityPageGuideContentDataTable->with([
        'authorityPage' => $authorityPage
    ])->html();
    
    return view('pages.authority-pages.show', [
        'authorityPage' => $authorityPage,
        'blogPosts' => $blogPosts,
        'tours' => $tours,
        'destinations' => $destinations,
        'keywordIntents' => $keywordIntents,
        'authorityContentDt' => $authorityContentDt,
        'accordionDt' => $accordionDt
    ]);
    

    Now, within your view, you can use {{$authorityContentDt->table()}} and {{$authorityContentDt->scripts()}} to include the DataTable HTML and scripts.