Laravel-datatables: [QUESTION] 2 tables with HTML Builder

Created on 19 Jan 2018  Â·  12Comments  Â·  Source: yajra/laravel-datatables

How can I use HTML Builder to display 2 tables in the same view?

it's possible?

Thank you

question

Most helpful comment

I suggest you go for a js script level on default config. This is how I do it on my projects too.

$.extend(true, $.fn.dataTable.defaults, {
    "dom": "<'row'<'col-md-4 col-sm-12'<'pull-left'f>><'col-md-8 col-sm-12'<'table-group-actions pull-right'B>>r><'table-container't><'row'<'col-md-12 col-sm-12'pli>>", // datatable layout
    "pagingType": "bootstrap_extended",
    "buttons": [],
    "renderer": "bootstrap",
    "searchDelay": 1500,
    "deferRender": true,
    "autoWidth": false, // disable fixed width and enable fluid table
    "pageLength": 10, // default records per page
    "language": { // language settings
        "lengthMenu": "<span class='dt-length-style'><i class='fa fa-bars'></i> &nbsp;View &nbsp;&nbsp;_MENU_ &nbsp;records&nbsp;&nbsp; </span>",
        "info": "<span class='dt-length-records'><i class='fa fa-globe'></i> &nbsp;Found&nbsp;<span class='badge bold badge-dt'>_TOTAL_</span>&nbsp;total records </span>",
        "infoEmpty": "<span class='dt-length-records'>No records found to show</span>",
        "emptyTable": "No data available in table",
        "infoFiltered": "<span class=' '>(filtered from <span class='badge bold badge-dt'>_MAX_</span> total records)</span>",
        "zeroRecords": "No matching records found",
        "search": "<i class='fa fa-search'></i>",
        "paginate": {
            "previous": "Prev",
            "next": "Next",
            "last": "Last",
            "first": "First",
            "page": "<span class=' '><i class='fa fa-eye'></i> &nbsp;Page&nbsp;&nbsp;</span>",
            "pageOf": "<span class=' '>&nbsp;of&nbsp;</span>"
        },
        "sProcessing": "Please wait..."
    }
});

All 12 comments

You mean using a single builder to display 2 tables? Maybe try cloning the original one?

@php ($dataTable2 = clone $dataTable)

{{ $dataTable->table(['id' => 'table1']) }}
{{ $dataTable2->table(['id' => 'table2']) }}

{{ $dataTable->scripts() }}
{{ $dataTable2->scripts() }}

@yajra Would you have a complete example using ajax in 2 tables with the code in the controller?

I try:

$html1 = $builder->ajax(route('usuario.test')) ->columns([
            ['data' => 'id', 'title' => '#', 'footer' => 'Id'],
            ['data' => 'nome', 'title' => 'Nome', 'footer' => 'Nome'],
            ['data' => 'created_at', 'title' => 'Created At', 'footer' => 'Created At'],
            ['data' => 'updated_at', 'title' => 'Updated At', 'footer' => 'Updated At']
        ]);

        $html2 = $builder->ajax(route('usuario.test2')) ->columns([
            ['data' => 'id', 'title' => '#', 'footer' => 'Id'],
            ['data' => 'nome', 'title' => 'Nome', 'footer' => 'Nome'],
            ['data' => 'created_at', 'title' => 'Created At', 'footer' => 'Created At'],
            ['data' => 'updated_at', 'title' => 'Updated At', 'footer' => 'Updated At']
        ]);

        return view('usuario::users', compact('html1', 'html2'));

Ajax test:

public function test(){
        try {
            return DataTables::of(Usuario::all())->toJson();
        } catch ( Exception $e ) {
            dd($e);
        }
    }

    public function test2(){
        try {
            return DataTables::of(Permission::all())->toJson();
        } catch ( Exception $e ) {
            dd($e);
        }
    }

view:

@section('content')
    <div class="row">
        <div class="col-md-12">
            <div class="box box-primary">
                <div class="box-header with-border">
                    Users
                </div> <!-- /.box-header -->
                <div class="box-body">
                    <div class="row">
                        <div class="col-md-12">
                            {!! $html1->table() !!}
                            {!! $html2->table() !!}
                        </div>
                    </div>
                </div>
            </div> <!-- /.box-body -->
        </div>
    </div>
@stop

@section('js')
{!! $html1->scripts() !!}
{!! $html2->scripts() !!}
@stop

without success .. if you can show me how to do it, I'll thank you.

You just need to set the table id as it must be unique to every table.

{!! $html1->table(['id' => 't1']) !!}
{!! $html2->table(['id' => 't2']) !!}

And how does the script work? I tried to do it in the form below, however the first table does not appear the information, the table is not drawn in case.

@section('content')
    <div class="row">
        <div class="col-md-12">
            <div class="box box-primary">
                <div class="box-header with-border">
                    Users
                </div>
                <div class="box-body">
                    <div class="row">
                        <div class="col-md-12">
                            <h1>TABELA 1</h1>
                            {!! $html1->table(['id' => 't1']) !!}
                        </div>
                    </div>
                    <div class="row">
                        <div class="col-md-12">
                            <h1>TABELA 2</h1>
                            {!! $html2->table(['id' => 't2']) !!}
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
@stop

@section('js')
{!! $html1->scripts() !!}
@stop

If I add {!! $html2->scripts() !!} gives the error:

DataTables warning: table id=t2 - Cannot reinitialise DataTable. For more information about this error, please see http://datatables.net/tn/3

EDIT:
It looks like the content is overlapping the other. The html1 data is not being passed, only html2.
Is that the right way to do it?

$html1 = $builder->ajax(route('usuario.test')) ->columns([
            ['data' => 'id', 'title' => '#', 'footer' => 'Id'],
            ['data' => 'nome', 'title' => 'Nome', 'footer' => 'Nome'],
            ['data' => 'created_at', 'title' => 'Created At', 'footer' => 'Created At'],
            ['data' => 'updated_at', 'title' => 'Updated At', 'footer' => 'Updated At']
        ])->addAction();

        $html2 = $builder->ajax(route('usuario.test2')) ->columns([
            ['data' => 'id', 'title' => '#', 'footer' => 'Id'],
            ['data' => 'created_at', 'title' => 'Created At', 'footer' => 'Created At'],
            ['data' => 'updated_at', 'title' => 'Updated At', 'footer' => 'Updated At']
        ]);

        return view('usuario::users', compact('html1', 'html2'));

I'd like to do something like this https://datatables.yajrabox.com/services/two-datatables, but using my controller without creating another file just for the datatables, because I'm working with modules and would like to centralize everything..

It would be possible?

or would it be possible to set the id directly in the "$builder"?

@marcelogarbin you might be using a same instance of the builder. I just tried this out and here is a working code for me.

Controllers

Route::get('dt', function() {
    $b1 = app(Builder::class)->columns(['id', 'first_name'])->ajax('dt/data')->setTableId('t1');
    $b2 = app(Builder::class)->columns(['id', 'first_name'])->ajax('dt/data')->setTableId('t2');

    return view('dt', compact('b1', 'b2'));
});

Route::get('dt/data', function () {
    return datatables(App\User::query())->toJson();
});

View

@extends('layouts.master')

@section('content')
    {{ $b1->table() }}
    {{ $b2->table() }}
@endsection

@push('scripts')
    {{$b1->scripts()}}
    {{$b2->scripts()}}
@endpush

@yajra Very good!
the call of my function was as follows public function users(Builder $builder){

So I changed $html1 = $builder->ajax(route('usuario.test')) to $html1 = app(Builder::class)->ajax(route('usuario.test'))

Worked perfectly!

What does theapp(Builder::class) do? Do I always have to use it that way?

Many thanks for your attention, I owe you 1 beer hahaha

EDIT: Another doubt, previously to add a button and check permissions I would do it this way:

->addColumn('action', function ($registro){
                    $edit   = null;
                    $delete = null;

                    $desenvolvimento = array_reduce($registro->grupos->toArray(), function($previouslyFound, $currentItem){
                        return ($currentItem['name'] == 'desenvolvimento') || $previouslyFound;
                    }, false);

                    if(Auth::user()->hasRole('desenvolvimento') || $desenvolvimento != true){
                        if(Auth::user()->hasPermissionTo($this->rota.'.edit')){
                            $edit   = '<a href="'. route($this->rota.'.edit', Hashids::encode($registro->id)) .'" class="btn btn-sm btn-primary" data-toggle="tooltip" data-placement="top" title="Editar"><i class="fa fa-pencil-square-o" aria-hidden="true"></i></a>';
                        }
                        if(Auth::user()->hasPermissionTo($this->rota.'.destroy')){
                            $delete =  Form::open(['route' => [$this->rota.'.destroy', Hashids::encode($registro->id)], 'method' => 'DELETE', 'class' => 'form-inline']).
                                '<button type="submit" class="btn btn-sm btn-danger btn-lixeira" data-id="'.$registro->id.'" data-toggle="tooltip" data-placement="top" title="Deletar"><i class="fa fa-trash-o" aria-hidden="true"></i></button>'.
                                Form::close();
                        }
                    }else{
                        $acao   = '<span data-toggle="tooltip" title="Você não possui permissão para editar esse usuário!"><i class="fa fa-info-circle" aria-hidden="true"></i></span>';
                    }

                    if(!isset($edit) && !isset($delete)){
                        $acao = '<span data-toggle="tooltip" title="Você não possui permissão para executar ações neste módulo!"><i class="fa fa-info-circle" aria-hidden="true"></i></span>';
                    }else{
                        $acao = $edit.$delete;
                    }

                    return '<div class="acao text-center">'.$acao.'</div>';
                })

How can I use this same logic in HTML Builder? Solved.

Is it also possible to set the parameters with a global/equal configuration for all instances?

Ex. When I call for example Builder this setting defaults:

->parameters([
            'paging' => true,
            'searching' => true,
            'info' => true,
            'searchDelay' => 350,
            //            'dom'          => 'Bfrtip',
            //            'buttons'      => ['export', 'print', 'reset', 'reload'],
            'language' => [
                'url' => url('vendor/datatables/Portuguese-Brasil.json')
            ],
        ]);

I suggest you go for a js script level on default config. This is how I do it on my projects too.

$.extend(true, $.fn.dataTable.defaults, {
    "dom": "<'row'<'col-md-4 col-sm-12'<'pull-left'f>><'col-md-8 col-sm-12'<'table-group-actions pull-right'B>>r><'table-container't><'row'<'col-md-12 col-sm-12'pli>>", // datatable layout
    "pagingType": "bootstrap_extended",
    "buttons": [],
    "renderer": "bootstrap",
    "searchDelay": 1500,
    "deferRender": true,
    "autoWidth": false, // disable fixed width and enable fluid table
    "pageLength": 10, // default records per page
    "language": { // language settings
        "lengthMenu": "<span class='dt-length-style'><i class='fa fa-bars'></i> &nbsp;View &nbsp;&nbsp;_MENU_ &nbsp;records&nbsp;&nbsp; </span>",
        "info": "<span class='dt-length-records'><i class='fa fa-globe'></i> &nbsp;Found&nbsp;<span class='badge bold badge-dt'>_TOTAL_</span>&nbsp;total records </span>",
        "infoEmpty": "<span class='dt-length-records'>No records found to show</span>",
        "emptyTable": "No data available in table",
        "infoFiltered": "<span class=' '>(filtered from <span class='badge bold badge-dt'>_MAX_</span> total records)</span>",
        "zeroRecords": "No matching records found",
        "search": "<i class='fa fa-search'></i>",
        "paginate": {
            "previous": "Prev",
            "next": "Next",
            "last": "Last",
            "first": "First",
            "page": "<span class=' '><i class='fa fa-eye'></i> &nbsp;Page&nbsp;&nbsp;</span>",
            "pageOf": "<span class=' '>&nbsp;of&nbsp;</span>"
        },
        "sProcessing": "Please wait..."
    }
});

For the action part, try using a partial view to extract the logic and make it reusable. See https://yajrabox.com/docs/laravel-datatables/master/add-column#view for ref.

Thread is closed. It was possible to run 2 tables via Ajax in the same view.

To leave the default DataTables setting with each call, I put the settings inside app/Providers/AppServiceProvider.php:

// Datatables
        Config::set('DTParametros', [
            'responsive'  => true,
            'autoWidth'   => false,
            'paging'      => true,
            'searching'   => true,
            'info'        => true,
            'order'       => [(isset($order))? $order : [0, 'desc']],
            'searchDelay' => 350,
            'language'    => [
                'url' => url('vendor/datatables/Portuguese-Brasil.json')
            ]
        ]);

I made a function to get the records via ajax that I would like, leaving it like this:

public function getRegistros($ativos = true, $campos = [], $order = [0, 'desc'])
    {

        config(['DTParametros.order' => $order]);

        $rota = ($ativos === true)? route($this->rota.'.ajaxListarRegistrosCadastrados') : route($this->rota.'.ajaxListarRegistrosDeletados');

        $html = app(Builder::class)
                ->parameters(config('DTParametros'))
                ->minifiedAjax($rota)
                ->columns($campos)
                ->setTableId(($ativos === true)? 'DTCadastrados' : 'DTDeletados');

        return $html;
    }

I call the function this way:

$cadastrados = $this->getRegistros(true, [
                ['data' => 'id', 'title' => '#'],
                ['data' => 'nome', 'title' => 'Nome'],
                ['data' => 'username', 'title' => 'Usuário'],
                ['data' => 'email', 'title' => 'E-mail'],
                ['data' => 'grupos', 'title' => 'Grupos'],
                ['data' => 'status', 'title' => 'Status'],
                ['data' => 'created_at', 'title' => 'Criado em'],
                ['data' => 'updated_at', 'title' => 'Atualizado em'],
                ['data' => 'action', 'title' => 'Ação', 'footer' => 'Ação', 'width' => '10%', 'orderable' => false, 'searchable' => false, 'printable' => false, 'class' => 'text-center']
            ]);

            $deletados   = $this->getRegistros(false,[
                ['data' => 'id', 'title' => '#'],
                ['data' => 'nome', 'title' => 'Nome'],
                ['data' => 'username', 'title' => 'Usuário'],
                ['data' => 'email', 'title' => 'E-mail'],
                ['data' => 'grupos', 'title' => 'Grupos'],
                ['data' => 'created_at', 'title' => 'Criado em'],
                ['data' => 'updated_at', 'title' => 'Atualizado em'],
                ['data' => 'deleted_at', 'title' => 'Deletado em'],
                ['data' => 'action', 'title' => 'Ação', 'footer' => 'Ação', 'width' => '10%', 'orderable' => false, 'searchable' => false, 'printable' => false, 'class' => 'text-center']
            ]);

Thank's @yajra

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ruchisheth picture ruchisheth  Â·  16Comments

ZAZmaster picture ZAZmaster  Â·  15Comments

webwizard02 picture webwizard02  Â·  17Comments

faisalhilmi picture faisalhilmi  Â·  18Comments

Arkhas picture Arkhas  Â·  15Comments