How can I use HTML Builder to display 2 tables in the same view?
it's possible?
Thank you
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.
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();
});
@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> View _MENU_ records </span>",
"info": "<span class='dt-length-records'><i class='fa fa-globe'></i> Found <span class='badge bold badge-dt'>_TOTAL_</span> 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> Page </span>",
"pageOf": "<span class=' '> of </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
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.