Optimal way to search columns from joined tables in yajra datatable - laravel

I am using yajra datatable in a laravel project to generate a list. My problem is: when I join a table and try to use a raw query to extract a column, it becomes unsearchable.
My table code:
$AAEListData = Entrepreneur::leftjoin('users', 'users.id', 'entrepreneurs.user_id')
->where('entrepreneurs.user_id', Auth::user()->id)
->groupBy('entrepreneurs.id')
->orderBy('entrepreneurs.created_at','desc')
->select([
'entrepreneurs.*',
'users.id as user',
DB::raw('CONCAT(IFNULL(users.user_first_name,"")," ",IFNULL(users.user_middle_name,"")," ",IFNULL(users.user_last_name,"")) as user_name')
]);
return Datatables::of($AAEListData)
->addColumn('action', function ($AAEListData) {
$view_btn = '<a href="' . url('entrepreneur/advance-against-expense-info/edit/' . Encryption::encodeId($AAEListData->id)) .
'" class="btn btn-xs btn-primary open" target="_blank" ><i class="fa fa-folder-open"></i> Open</a>';
return $view_btn;
})
->rawColumns(['action'])
->make(true);
The problem starts with the column user_name.
columns: [
{data: 'name', name: 'name'},
{data: 'phone', name: 'phone'},
{data: 'status', name: 'status'},
{data: 'user_name', name: 'user_name'},
{data: 'action', name: 'action'},
],
Whenever I try to search something, an error says column entrepreneurs.user_name not found. That is because it is not in that table, it comes from a joined table users. Can yajra datatable not detect this? I have searched this issue on the net and most suggestions ask converting the query collection to an array or simple avoid DB::RAW altogether. Neither solution is optimal for my situation but I am willing to do it the hard way if no other choice remains. My question is: is there a simpler way of informing datatable about which column belongs in which table?
N.B: no, simply doing users.user_name does not work. That is the first thing I tried, in both controller and blade, neither worked.

If your using the latest version you should define the name: table.column pattern.

I think your problem is not about Yajra. "name: table.column" pattern is working to me("yajra/laravel-datatables-oracle": "^9.19").
I guess there is no column of user_name in tables of users and entrepreneurs.
it won't work below.
SELECT CONCAT(IFNULL(users.user_first_name,"")," ",IFNULL(users.user_middle_name,"")," ",IFNULL(users.user_last_name,"")) as user_name
FROM USERS
WHERE user_name = [userName];
You should make a subquery.
SELECT
t1.*,
users.id as user,
FROM
(SELECT entrepreneurs.*,
CONCAT(IFNULL(users.user_first_name,"")," ",IFNULL(users.user_middle_name,"")," ",IFNULL(users.user_last_name,"")) as user_name
FROM entrepreneurs
WHERE entrepreneurs.user_id = Auth::user()->id
) as t1
LEFT JOIN users on users.id = t1.user_id
WHERE t1.user_name = [userName]
GROUP By t1.id
----> Yajra subquery example
"name: table.column" pattern
Blade
columns: [
{ data: 'delivery_type', name: 't2.delivery_type' },
],
Controller
if ($userType == 'HFF0601' || $userType == 'HFF0602') {
$defaultQuery =
datatables()->of(Delivery::select([
'deliveries.*',
'deliveries.status as status_code',
't1.email',
't1.user_type',
't2.group_no',
't2.delivery_type',
't2.delivery_type as delivery_type_code'
])->join('delivery_groups AS t2', 'deliveries.grp_id', '=', 't2.id')
->leftJoin('users AS t1', 'deliveries.user_id', '=', 't1.id'));
}
return $defaultQuery
->filter(function ($query) use ($request) {
.
.
.
.

I tested my code and it works. but the concat in the where statement may have performance issues.
DB::raw("CONCAT(t1.name,' ',t1.last_name) as fullname")
->orWhereRaw("CONCAT(t1.name,' ',t1.last_name) like ?", "%{$serchTerms}%")
{ data: 'fullname', name: 'fullname' },
if ($userType == 'HFF0601' || $userType == 'HFF0602') {
$defaultQuery = datatables()
->of(Delivery::select(
[DB::raw("CONCAT(t1.name,' ',t1.last_name) as fullname"),
'deliveries.*',
'deliveries.status as status_code',
't1.email',
't1.user_type',
't2.group_no',
't2.delivery_type',
't2.delivery_type as delivery_type_code'])
->join('delivery_groups AS t2', 'deliveries.grp_id', '=', 't2.id')
->leftJoin('users AS t1', 'deliveries.user_id', '=', 't1.id'));
}
return $defaultQuery
->filter(function ($query) use ($request) {
//Filtering date range
//...
//Global Search
if ($request->has('searchterms')) {
$serchTerms = $request->searchterms;
$query->where(function($q) use($serchTerms) {
$q->where('shipping_no', 'like', "%{$serchTerms}%")
->orWhere('order_no', 'like', "%{$serchTerms}%")
->orWhere('email', 'like', "%{$serchTerms}%")
->orWhereRaw("CONCAT(t1.name,' ',t1.last_name) like ?", "%{$serchTerms}%")
->orWhere('from_name', 'like', "%{$serchTerms}%")
->orWhere('to_name', 'like', "%{$serchTerms}%")
->orWhere('desc1', 'like', "%{$serchTerms}%")
->orWhere('status', 'like', "%{$serchTerms}%");
});
}
})
columns: [
{ data: 'checkbox', name: 'checkbox', orderable: false, searchable: false},
{ data: 'id', name: 'id' },
{ data: 'group_no', name: 'group_no' },
{ data: 'delivery_type', name: 't2.delivery_type' },
{ data: 'user_id', name: 'user_id' },
{ data: 'email', name: 'email' },
{ data: 'order_no', name: 'order_no' },
{ data: 'shipping_no', name: 'shipping_no' },
{ data: 'from_name', name: 'from_name' },
{ data: 'to_name', name: 'to_name' },
{ data: 'shipping_charge', name: 'shipping_charge' },
{ data: 'status', name: 'status' },
{ data: 'fullname', name: 'fullname' },
{ data: 'action', name: 'action', orderable: false },
],

Related

How to send parameters from datatable to controller Laravel

I have a datatable in my blade view Laravel, I user click the blue button it will open new page and show all task with same user_id as clicked before
I'm trying to pass user_id value to controller. I have do this following code
My routes
Route::get('/detail/{user_id}', [PageController::class, 'UserTask'])->name('user.task');
My datatable code in blade file
$(function() {
var user_id = $(this).data('user_id'); //have different value from each rows
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
var table = $('.data-table').DataTable({
processing: true,
serverSide: true,
ajax: "{{ route('user.task') }}" + '/' + user_id,
columns: [{
data: 'DT_RowIndex',
name: 'DT_RowIndex',
orderable: false,
searchable: false,
},
{
data: 'title',
name: 'title',
orderable: false,
},
{
data: 'content',
name: 'content',
orderable: false,
visible: false,
},
{
data: 'progress',
name: 'progress'
},
{
data: 'status',
name: 'status'
},
{
data: 'target_selesai',
name: 'target_selesai'
},
{
data: 'action',
name: 'action',
orderable: false,
searchable: false
},
]
});
});
my controller
public function UserTask($user_id)
{
$data = Post::where('user_id', $user_id)->latest()->get();
return Datatables::of($data)
->addIndexColumn()
->addColumn('action', function ($row) {
$id = $row->id;
// $this->actionButton($row->id);
$btn = ' <span class="fas fa-info"></span>';
return $btn;
})->addColumn('target_selesai', function ($row) {
//...
})
->addColumn('progress', function ($row) {
//...
})->addColumn('status', function ($row) {
//...
})
->rawColumns(['action', 'progress', 'status'])
->make(true);
return view('detail');
}
But, it will return error Missing required parameter for [Route: user.task]
If I remove all the parameter {user_id}, from routes, ajax routes, and change the
public function UserTask($user_id)
{
$data = Post::where('user_id', $user_id)->latest()->get();
into
public function UserTask()
{
$data = Post::where('user_id', 1000000002)->latest()->get();
The program will works perfectly, how can I pass the user_id value from datatable to controller?
You cannot use "{{ route('user.task') }}" + '/' + user_id as route() function renders the route in the server while you're trying to change it in the client side. Send the user_id via as data with ajax and retrieve it using request()->get('user_id')

laravel datatables search in addColumn

I use laravel/datatables to list data.
I manipulated my datalist with addColumn function.
However I am not able to use search in view for added columns.
Because search is working according to database rows.
Datatables works fine but in the view search area is not working. Because there isnt any fullname row in database table.
Here you can find my codes (I want to search for fullname but I can't)
Order Model
public function getFullname()
{
return json_decode($this->getAttribute('delivery_adress'))->fullname;
}
OrderController.php
if ($request->ajax()) {
return datatables()->of(Order::query())
->addColumn('fullname', function (Order $order) {
return $order->getFullname();
})->addColumn('city', function (Order $order) {
return $order->getCity();
})->addColumn('product_id', function (Order $order) {
return $order->product->title;
})->make(true);
}
Orders Blade / Datatables code
"pageLength": 10,
processing: true,
serverSide: true,
ajax: 'orders',
columns: [
{ data: 'id', name: 'id'},
{ data: 'fullname', name: 'fullname', defaultContent: '-' , orderable: false },
{ data: 'city', name: 'city', defaultContent: '-', orderable: false },
{ data: 'product_id', name: 'product_id', className: 'd-none d-sm-table-cell', defaultContent: '-' },
{ data: 'totalPrice', name: 'totalPrice', className: 'd-none d-sm-table-cell', defaultContent: '-' },
],
edit:
Finally, I found solution
{data: 'added_column', name: 'actual_column_name'}
https://github.com/yajra/laravel-datatables/issues/139#issuecomment-275326787
Finally, I found solution
{data: 'added_column', name: 'actual_column_name'}
https://github.com/yajra/laravel-datatables/issues/139#issuecomment-275326787
Make sure to have relationship into Order model like this:
public function user()
{
return $this->belongsTo('App\User');
}
Try to update like this :
...
->addColumn('fullname', function (Order $order) {
return $order->user->fullname;
})
...
change status
serverSide : false
"pageLength": 10,
processing: true,
serverSide: false,
ajax: 'orders',
columns: [
{ data: 'id', name: 'id'},
{ data: 'fullname', name: 'fullname', defaultContent: '-' , orderable: false },
{ data: 'city', name: 'city', defaultContent: '-', orderable: false },
{ data: 'product_id', name: 'product_id', className: 'd-none d-sm-table-cell', defaultContent: '-' },
{ data: 'totalPrice', name: 'totalPrice', className: 'd-none d-sm-table-cell', defaultContent: '-' },
],

Row Group Server Side Yajra DataTables

i have problem with yajra datatables to make row group in server side. I want row group show all employee in companies.name. and my current code like this:
public function index(DataTablesBuilderService $builder)
{
$columns = [
'name' => [
'title' => "company",
'name' => 'companies.name'
];
$dataTables = $builder
->setUrl(route('api.employee_details.data_tables', request()->all()))
->withIndex()
->setColumns($columns);
return view('employee_details.index')->with([
'dataTables' => $dataTables,
]);
}
and in blade i just call datatable like this
{!! $dataTables->table(['class' => 'table table-bordered','style' => 'width:100%', 'cellspacing' => '0']) !!}
and the script like this
{!! $dataTables->scripts() !!}
If i following the tutorial on https://datatables.yajrabox.com/eloquent/master, its possible to make row group but i dont know how to implement in server side. But is so different with my code in blade. Tutorial call datatable like this.
var template = Handlebars.compile($("#details-template").html());
var table = $('#users-table').DataTable({
processing: true,
serverSide: true,
ajax: 'https://datatables.yajrabox.com/eloquent/master-data',
columns: [
{
"className": 'details-control',
"orderable": false,
"searchable": false,
"data": null,
"defaultContent": ''
},
{data: 'id', name: 'id'},
{data: 'name', name: 'name'},
{data: 'email', name: 'email'},
{data: 'created_at', name: 'created_at'},
{data: 'updated_at', name: 'updated_at'}
],
order: [[1, 'asc']]
});
// Add event listener for opening and closing details
$('#users-table tbody').on('click', 'td.details-control', function () {
var tr = $(this).closest('tr');
var row = table.row(tr);
var tableId = 'posts-' + row.data().id;
if (row.child.isShown()) {
// This row is already open - close it
row.child.hide();
tr.removeClass('shown');
} else {
// Open this row
row.child(template(row.data())).show();
initTable(tableId, row.data());
tr.addClass('shown');
tr.next().find('td').addClass('no-padding bg-gray');
}
});
function initTable(tableId, data) {
$('#' + tableId).DataTable({
processing: true,
serverSide: true,
ajax: data.details_url,
columns: [
{ data: 'id', name: 'id' },
{ data: 'title', name: 'title' }
]
})
}
and the result like this and i expected like this to but in datatables server side
Thank you if you can help to help me and explain how to solve the problem code
Injecting this in your DataTable options may help you (I've tried and it's working in my case)
$(selector).DataTable({
startRender: function (rows, group) {
var grpName = rows.data().pluck('company')
.reduce(function (a, b) {
return (b === null ? '' : b);
}, '');
return $('<tr/>')
.append('<td colspan="' + columns.length + '" class="text-left"><span class="ml-10px">' + grpName + '</span></td>');
},
endRender: null,
dataSrc: 'company'
})

Laravel Datatables search on nested Relationship

I'm currently using datatabels 7.0 and Laravel 5.4
data in my grid is showing correctly but when I want to search on nested relationship column I got below error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'course_semester.semester.name' in 'where clause' (SQL: select count(*) as aggregate from (select '1' as `row_count` from `videos` where LOWER(`videos`.`id`) LIKE %%te%% and LOWER(`videos`.`name`) LIKE %%te%% and LOWER(`course_semester`.`semester`.`name`) LIKE %%te%%) count_row_table)
Here is my code
Controller
$videos = Video::with(['course_semester' => function ($query) {
return $query->with('course', 'semester');
}])->select('videos.*');
return Datatables::of($videos)
->addColumn('check', '<input type="checkbox" name="selected-videos" value="{{$id}}">')
->escapeColumns([])
->make(true);
Javascript
columns: [
{ data: 'check' , name: 'check',orderable: false, searchable: false },
{ data: 'id', name: 'videos.id' },
{ data: 'name', name: 'videos.name' },
{ data: 'course_semester.semester.name', name: 'course_semester.semester.name'},
{ data: 'course_semester.course.name', name: 'course_semester.course.name'},
{ data: 'status', name: 'videos.status' },
{ data: 'comment', name: 'videos.comment' },
{ data: 'video_date', name: 'videos.video_date' },
]
Can anyone help me and notice my problem?
Thanks in advance.
Because of using select() here, you do not load the relationship. Also, use dot syntax for nested eager loading:
$videos = Video::with(['course_semester', 'course_semester.course'])
1- dataTable function
public function dataTable($query)
{
return datatables()
->eloquent($query)
->addColumn('BulkSelection', function ($category)
{
->addColumn('company', function ($category)
{
return $category->company ? $category->company->name : 'No Company';
})
->rawColumns(['action', 'company', 'createdAt','BulkSelection']);
}
2- query function
public function query(Category $model)
{
return $model->with('company:id,name')->select('categories.*')->newQuery();
}
3- getColumns function
$getCols = [
'id',
'name',
'company'=> [
'data'=>'company',
'name'=>'company.name'
],
'createdAt' => [
'name'=>'created_at',
'searchable' => false
],
'action' => [
'exportable' => false,
'searchable'=>false,
'orderable' => false
]
];
return $getCols;
If you just need to load the data from relation tables, use the below code
$videos = Video::with('course_semester','course', 'semester')->select('videos.*');
return Datatables::eloquent($videos)
->addColumn('check', function(Video $v){
return '<input type="checkbox" name="selected-videos" value="{{$v->id}}">'
})
->rawColumns(['check'])
->make(true);
And in script, you can call relation values as ,
{data: 'course_semester.id'},
{data: 'course.name'},
{data: 'semester.name'},
$getCols = [
'title',
'Images' => [
'name'=>'images_count',
'data'=>'images_count',
'searchable'=>false
],
'price' => ['name'=>'start_price', 'data'=>'start_price'],
'reserve_price',
'Category' => [
'data'=>'show_category',
'name'=>'categories.name',
'searchable'=>false
],
'created_by' => [
'name'=>'user.name',
],
'createdAt' => [
'name'=>'created_at',
'searchable' => false
],
'action' => [
'exportable' => false,
'searchable'=>false,
'orderable' => false
]

Laravel DataTables search in column generated with DB::raw

I have the following issue in Laravel DataTables (yajra/laravel-datatables
):
I can't search (filter) in a column generated with DB::Raw.
Also I can't search with Global search function.
In my Laravel Controller:
$inputs = Input_::join('companies', 'companies.id', '=', 'inputs.company_id')
->leftjoin('inputs_details', 'inputs_details.input_id', '=', 'inputs.id')
->select(array('inputs.id as id',
'inputs.created_at as created_at',
'inputs.updated_at as updated_at',
'inputs.input_at as input_at',
'companies.name',
'inputs.documents as documents',
DB::raw("SUM(inputs_details.quantity*inputs_details.price_input*(1+inputs_details.VAT/100)) as input_total")
))
->groupBy('inputs.id')
->orderBy('inputs.input_at', 'DESC');
return Datatables::of($inputs)
->remove_column('id')
->make(true);
In my View:
$('#inputs-table').DataTable({
processing : true,
serverSide : true,
ajax: '{{ URL::to('employee/inputs/data/') }}',
columns: [
{data: 'created_at', name: 'inputs.created_at', orderable: false},
{data: 'updated_at', name: 'inputs.updated_at', orderable: false},
{data: 'input_at', name: 'inputs.input_at', orderable: false},
{data: 'name', name: 'companies.name', orderable: false},
{data: 'documents', name: 'inputs.documents', orderable: false},
{data: 'input_total', name: 'input_total', orderable: false, searchable: true},
{data: 'reports', name: 'reports', orderable: false, searchable: false},
{data: 'actions', name: 'actions', orderable: false, searchable: false}
],
initComplete: function () {
this.api().columns().every(function () {
var column = this;
var input = document.createElement("input");
$(input).appendTo($(column.footer()).empty())
.on('change', function () {
var val = $.fn.dataTable.util.escapeRegex($(this).val());
column.search(val ? val : '', true, false).draw();
});
});
} });
You have to put the filterColumn action in your datatable.
$inputs = Input_::join('companies', 'companies.id', '=', 'inputs.company_id')
->leftjoin('inputs_details', 'inputs_details.input_id', '=', 'inputs.id')
->select(array('inputs.id as id',
'inputs.created_at as created_at',
'inputs.updated_at as updated_at',
'inputs.input_at as input_at',
'companies.name',
'inputs.documents as documents',
DB::raw("SUM(inputs_details.quantity*inputs_details.price_input*(1+inputs_details.VAT/100)) as input_total")
))
->groupBy('inputs.id')
->orderBy('inputs.input_at', 'DESC');
return Datatables::of($inputs)
->remove_column('id')
->filterColumn('input_total', function($query, $keyword) {
$query->whereRaw("SUM(inputs_details.quantity*inputs_details.price_input*(1+inputs_details.VAT/100)) = ?", $keyword);
})
->make(true);

Resources