Laravel Datatables search on nested Relationship - laravel

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
]

Related

Optimal way to search columns from joined tables in yajra datatable

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 },
],

Display Each Column sum on footer Yajra Laravel

The following screenshot shows the list of database results by enabling server-side processing. It shows the column total computed by using the Yajra DataTables.
HTML Code for DataTables with Column Total
To display the footer using html builder, pass true as 2nd argument on $builder->table([], true) api.
{!! $dataTable->table([], true) !!}
script
update th values
#push('scripts')
{!! $dataTable->scripts() !!}
<script>
var hours = JSON.parse("{{json_encode($hours)}}");
$(document).ready(function(){
$("tfoot tr>th:nth-child(2)").text("Total")
for (let i = 0; i < hours.length; i++) {
$('tfoot tr>th:nth-child('+ (i+3) +')').text(hours[i])
}
})
</script>
#endpush
Report Datatable File
In Query function we are getting reports record from database and use query result in dataTable function make column according to our requirement and finally set values to getColumns function.
public function dataTable($query)
{
$reports = ($query['data']);
return datatables()->make($reports)
->addColumn('name', function ($reports) {
return isset($reports['user_name']) ? $reports['user_name'] : null;
})
->addColumn('monday', function ($reports) {
return isset($reports['Mon']) ? ($reports['Mon']) : '-';
})
->addColumn('tuesday', function ($reports) {
return isset($reports['Tue']) ? $reports['Tue'] : '-';
})
->addColumn('wednesday', function ($reports) {
return isset($reports['Wed']) ? $reports['Wed'] : '-';
})
->addColumn('thursday', function ($reports) {
return isset($reports['Thu']) ? $reports['Thu'] : '-';
})
->addColumn('friday', function ($reports) {
return isset($reports['Fri']) ? $reports['Fri'] : '-';
})
->addColumn('total', function ($reports) {
return (isset($reports['Mon']) ? $reports['Mon'] : 0) +
(isset($reports['Tue']) ? $reports['Tue'] : 0) +
(isset($reports['Wed']) ? $reports['Wed'] : 0) +
(isset($reports['Thu']) ? $reports['Thu'] : 0) +
(isset($reports['Fri']) ? $reports['Fri'] : 0);
})
->addIndexColumn();
}
public function query(Lot $model)
{
$data = Reports.....;
return compact('data');
}
public function html()
{
return $this->builder()
->setTableId('userrequestdatatable-table')
->columns($this->getColumns())
->minifiedAjax()
->dom('Bfrtip')
->orderBy(1)
->buttons(
Button::make('export'),
);
}
protected function getColumns()
{
return [
'#' => [
'data' => 'DT_RowIndex',
'name' => 'DT_RowIndex',
'orderable' => false,
'searchable' => false
],
'user name'=> [
'data' => 'name',
'name' => 'name',
],
'monday'=> [
'data' => 'monday',
'name' => 'monday',
],
'tuesday'=> [
'data' => 'tuesday',
'name' => 'tuesday',
],
'wednesday'=> [
'data' => 'wednesday',
'name' => 'wednesday',
],
'thursday'=> [
'data' => 'thursday',
'name' => 'thursday',
],
'friday'=> [
'data' => 'friday',
'name' => 'friday',
],
'total'=> [
'data' => 'total',
'name' => 'total',
]
];
}

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 datatable relations error print

Problem is how to print(show) Topic's name in View. and i tried this topic->topic_name still got error.
Model of Vote
protected $fillable = [
'topic_id' ,'question', 'answer', 'lastname', 'firstname', 'identity', 'user_id',
];
public function topic(){
return $this->belongsTo('App\Topic');
}
Model of Topic
protected $fillable = [
'topic_name',
];
public function votes(){
return $this->hasMany('App\Vote');
}
APIController#getColumnSearchData
$customers = Vote::select(['id', 'topic_id', 'question', 'answer','lastname','firstname','identity', 'user_id', 'created_at']);
return Datatables::of($customers)->make(true);
View
processing: true,
serverSide: true,
ajax: '{{ route('api.column_search') }}',
columns: [
{ data: 'id', name: 'id' },
{ data: 'topic_name', name: 'topic_name' }, there is error
... ...,
],
try this:
// controller file:
$customers = Vote::with('topic')->get();
return Datatables::of($customers)->make(true);
//view:
processing: true,
serverSide: true,
ajax: '{{ route('api.column_search') }}',
columns: [
{ data: 'id', name: 'id' },
{ data: 'topic.topic_name', name: 'topic.topic_name' }, there is error
... ...,
],

How to filter for just one customer with yajra datatables

I have a customers table with each record linking to a customer contact:
http://localhost/untdchem/public/home/customers/contacts/1809
When I click on the above link, I want to display all the contacts for customer 1809 only in a datatable. I am trying to pass the customer ID somehow so I can filter for that customer only. I can fill the table with all the contacts but i want to just load for that customer.
Routes:
//Customer Contacts
Route::get('home/customers/contacts', ['as' => 'customers.contacts', 'uses' => 'CustomerContactsController#index']);
Route::get('home/customers/contacts/data', ['as' => 'customers.contacts.data', 'uses' => 'CustomerContactsController#anyData']);
In my controller:
public function index()
{
// GET request to index
return view('pages.customer_contacts.index');
}
public function anyData()
{
$contacts = customer_contact::select(['CustContactFName','CustContactLName','CustContactCountryCode','CustContactExtension','CustContactPhone','CustContactEmail','CustContactType']);
return Datatables::of($contacts)->make(true);
}
In my view:
<script>
$(function() {
$('#customer-contacts-table').DataTable({
processing: true,
serverSide: true,
ajax: '{!! route('customers.contacts.data') !!}',
columns: [
{ data: 'CustContactFName', name: 'CustContactFName'},
{ data: 'CustContactLName', name: 'CustContactLName'},
{ data: 'CustContactCountryCode', name: 'CustContactCountryCode'},
{ data: 'CustContactExtension', name: 'CustContactExtension'},
{ data: 'CustContactPhone', name: 'CustContactPhone'},
{ data: 'CustContactEmail', name: 'CustContactEmail'},
{ data: 'CustContactType', name: 'CustContactType'}
//{ data: 'action', name: 'action', orderable: false, searchable: false}
],
order: [[0, "desc" ]]
});
});
</script>
Routes
Route::get('home/customers/contacts/{id}', ['as' => 'customers.contacts', 'uses' => 'CustomerContactsController#index']);
Route::get('home/customers/contacts/data/{id}', ['as' => 'customers.contacts.data', 'uses' => 'CustomerContactsController#anyData']);
Controller
I am assuming there is CustId field that identifies which customer the contact record is assigned to. If your structure is different, adjust accordingly.
public function index($id) {
// GET request to index
return view('pages.customer_contacts.index', compact('id'));
}
public function anyData($id){
$contacts = customer_contact::select([
'CustContactFName',
'CustContactLName',
'CustContactCountryCode',
'CustContactExtension',
'CustContactPhone',
'CustContactEmail',
'CustContactType'
])
->where('CustId', '=', $id);
return Datatables::of($contacts)->make(true);
}
JavaScript
Update the line with ajax option:
ajax: '{!! route('customers.contacts.data', ['id' => $id]) !!}',
The correct solution below:
public function index($CustID = null, Request $request)
{
if ($request->ajax()) {
$contacts = customer_contact::select(['CustContactFName','CustContactLName','CustContactCountryCode','CustContactExtension','CustContactPhone','CustContactEmail','CustContactType']);
if ($CustID) {
$contacts->where('CustID', $CustID);
}
//dd($contacts);
return Datatables::of($contacts)
->addColumn('action', function ($contacts) {
$links="";
$links.='Edit | ';
$links.='<a class="delete" href="'.url('home/customers/contacts/delete', [$contacts->CustID]).'">Delete</a> | ';
return $links;
})->make(true);
}
return view('pages.customer_contacts.index', compact('CustID'));
}
<script>
$(function() {
$('#customer-contacts-table').DataTable({
processing: true,
serverSide: true,
ajax: '{!! route('customers.contacts', $CustID) !!}',
columns: [
{ data: 'CustContactFName', name: 'CustContactFName'},
{ data: 'CustContactLName', name: 'CustContactLName'},
{ data: 'CustContactCountryCode', name: 'CustContactCountryCode'},
{ data: 'CustContactExtension', name: 'CustContactExtension'},
{ data: 'CustContactPhone', name: 'CustContactPhone'},
{ data: 'CustContactEmail', name: 'CustContactEmail'},
{ data: 'CustContactType', name: 'CustContactType'},
{ data: 'action', name: 'action', orderable: false, searchable: false}
],
order: [[0, "desc" ]]
});
});
</script>

Resources