Laravel-datatables: how to search in a column generated by addColumn?

Created on 3 Aug 2015  ·  22Comments  ·  Source: yajra/laravel-datatables

First, great job for this amazing package.

I have a small problem:

I added a new custom column in your demo file: .../eloquent/add-edit-remove-column, I want to search/filter for that column, but I get an error in browser when I input everything.

Is there a solution to search/filter in a custom column and after that to add a search input text for every column in table, including for custom_column?

Error in FireBug console:

  <span class="exception_message">SQLSTATE[42S22]: Column not found: 1054 Champ
 &#039;new_column&#039; inconnu dans where clause (SQL: select count(*) as aggregate from (select &#039
;1&#039; as row_count from `users` where (LOWER(`id`) LIKE %b% or LOWER(`name`) LIKE %b% or LOWER(`email
`) LIKE %b% or LOWER(`created_at`) LIKE %b% or LOWER(`updated_at`) LIKE %b% or LOWER(`new_column`) LIKE
 %b%)) count_row_table)</span>

Code from Controller:

    public function getAddEditRemoveColumnData()
    {
        $users = User::select(['id', 'name', 'email', 'password', 'created_at', 'updated_at']);

        return Datatables::of($users)
                                 ->addColumn('new_column' , 'ABC')
                                  ->make(true)
    }

Code from Javascript:

    $('#users-table').DataTable({
        processing: true,
        serverSide: true,
        ajax: '{{ url("eloquent/add-edit-remove-column-data") }}',
        columns: [
            {data: 'id', name: 'id'},
            {data: 'name', name: 'name'},
            {data: 'email', name: 'email'},
            {data: 'created_at', name: 'created_at'},
            {data: 'updated_at', name: 'updated_at'},
            {data: 'new_column', custom: 'new_column', orderable: true, searchable: true}
        ]
    });

Most helpful comment

@marioene, you cannot search on addColumn if the data is not from the database. A workaround for this is to add the column on your select statement like below. No need to use addColumn.

$users = User::select([
'id', 'name', 'email', 'password', 'created_at', 'updated_at',
DB::raw("'ABC' as new_column")
]);

Note: You may have to write a custom filterColumn for it to work. Just make sure the sql generated is working and it should work with the package too.

All 22 comments

@marioene, you cannot search on addColumn if the data is not from the database. A workaround for this is to add the column on your select statement like below. No need to use addColumn.

$users = User::select([
'id', 'name', 'email', 'password', 'created_at', 'updated_at',
DB::raw("'ABC' as new_column")
]);

Note: You may have to write a custom filterColumn for it to work. Just make sure the sql generated is working and it should work with the package too.

Closing due to inactivity and suggested workaround above should fix the issue. Thanks!

@yajra I followed your suggestion to first add a calculated column using 'select' (in Controller)

$staffData = Staff::select('id', 'staff_id', \DB::raw('concat(first_name, " ", middle_name, " ", last_name) as full_name'), 'department_name', 'status');

Then I added a custom filter (in Controller)

$dt = Datatables::of($staffData);
return $dt->filterColumn('full_name', function($query, $keyword) {
            $query->whereRaw("CONCAT(first_name, ' ', middle_name, ' ', last_name) like ?", ["%{$keyword}%"]);
        })->make(true);

When I first load the the page, data table is rendered properly by when I do search using the global search input text box, an error is being thrown

Ajax error. http://datatables.net/tn/7

Can you please let me know where I might be making mistake.

@AshishGupta001 try inspecting the ajax request using chrome dev tools or firebug. It will give you a hint on what's causing the issue. Most probably, an sql exception issue.

@yajara Thanks for your quick response.
While implementing the global search for a 'calculated' column (in my case 'full_name') I took reference to
1) Issue 168 : https://github.com/yajra/laravel-datatables/issues/168
2) Example: https://datatables.yajrabox.com/eloquent/post-column-search

Before I added the custom 'filterColumn()' for my datatable, I was getting SQL exception complaining for missing column 'full_name' in the table. Then I added below code to add a custom filter for 'calculated' column (in my case 'full_name') as below

$dt->filterColumn('full_name', function($query, $keyword) {
       $query->whereRaw("CONCAT(staff.first_name, ' ', staff.middle_name, ' ', staff.last_name) like ?", ["%{$keyword}%"]);
});

return $dt->make(true);

Now I get following error in the log

mb_strtolower() expects parameter 1 to be string, object given in file ......./vendor/laravel/framework/src/Illuminate/Support/Str.php#162

Appreciate if you can help debug this issue.

@AshishGupta001 what version are you using? Your code looks fine to me.

@yajra Thanks for confirming. Versions are as below

PHP - 5.5.38-3
Laravel - 5.0.34
Datatables - yajra/laravel-datatables-oracle: ^6.3 (as in composer.json)

It seems in 'getOrMethod' in Helper class, exception is being thrown as it is trying to convert to lower a "clouser" passed as a input param.

public static function getOrMethod($method) {
   if (! Str::contains(Str::lower($method), 'or')) {
      return 'or' . ucfirst($method);
   }
      return $method;
}

'$method' is a clouser as passed function($query, $keyword), as below

Closure {#864
  reflection: """
    Closure [ <user> public method App\Http\Controllers\{closure} ] {\n
      @@ /var/www/html/XYZ/app/Http/Controllers/StaffHistoryController.php 310 - 313\n
    \n
      - Parameters [2] {\n
        Parameter #0 [ <required> $query ]\n
        Parameter #1 [ <required> $keyword ]\n
      }\n
    }\n
    """
}

Though I could not figure out the issue I faced, I was able to find out the way around this specific use case. Thanks for the hints available here.

View: Have the following in the View within the script tag

{ data: 'full_name', name: 'full_name', searchable: false },
{ data: 'first_name', name: 'first_name', searchable: true, visible: false },
{ data: 'middle_name', name: 'middle_name', searchable: true, visible: false },
{ data: 'last_name', name: 'last_name', searchable: true, visible: false }

Controller: Fetch first_name etc in the SQL query along with rest of the column values.

@AshishGupta001 glad you figured that out. That is what I used to do too since Laravel 4.2 version. 👍

@AshishGupta001 Good solution!

@yajra Can we search an added column using the addColumn which it's data coming from the database but we are not adding this column in the JS ?

Or we should add it to the JS and make it invisible but searchable ?

Some ways I can think of:

  1. Add it to js and make it invisible and searchable as you said.
  2. Use filterColumn to manually handle the searching of added column.
  3. Declare it this way:
{data: 'added_column', name: 'actual_column_name'}

Thanks for your quick response @yajra

I was already trying the second solution but I noticed this added column is not considered in the query.

Any thoughts ?

Make sure you did not add searchable: falseon that column.

This is how I added the column ->addColumn('company_name', function($deal) { return $deal->company_name; })

And the global search query as $dataTable->filterColumn('company_name', 'where', "like", ["%$keyword%"]);

Can we pass the searchable: false in the backend?

searchable: false is on the client-side js.

BTW, what version are you using?

Ah ok. So we still need to use the first way you mentioned, with this way.
I'm using v6.17.0

I am having the same issue as @AshishGupta001 unfortunately the client-side trick does not cut it as the column is not sortable.
I have explored the filterColumn alternative but could not get it to work too.
using "yajra/laravel-datatables-oracle": "~9.0"

controller method:

    public function getAccounts(Request $request)
    {
        if ($request->ajax()) {
            $accounts = Account::with('current_marketer')->select([
                '*',
                DB::raw("CONCAT(accounts.lastname,' ',accounts.firstname) as fullname"),
            ]);
            return Datatables::of(Account::query()->with('current_marketer'))
            ->addColumn('marketer', function(Account $account){
                return $account->current_marketer->name;
            })
            ->addColumn('fullname', function($account){
                return '<a href="'.route('account.clients.show', $account->account_number).'" class="hover:underline" target="_blank">'. $account->fullname.'</a>';
            })
            ->filterColumn('fullname', function($query, $keyword) {
                $sql = "CONCAT(accounts.lastname,' ',accounts.firstname)  like ?";
                $$query->whereRaw($sql, ["%{$keyword}%"]);
            })
            ->rawColumns(['fullname'])
            ->editColumn('created_on', function(Account $account) {
                return Carbon::parse($account->created_on)->format('jS F, Y');
            })
            ->toJson();
        }
        return view('datatables.accounts.index');
    }

Blade js:

 $('#accounts-table').DataTable({
          "processing": true,
          "serverSide": true,
          "ajax": '{{ route('accounts.get') }}',
          "columns": [
            { data: "id" },
            { data: "account_number" },
            { data: 'fullname'},
            { data: "marketer" },
            { data: "created_on" },
          ]
        });

Exception: when searching or sorting is attempted:

yajraIssue

as it turns out the issue with that exception was my fault; I had a double '$$' sign within my filterColumn method.
yajra_issue_fix_1

That didn't fix my sorting problem though. I still need to know :

  1. how to make the column sort-able
  2. how to search and sort related columns another look at the docs cleared this for my use case

@seewhy17 you can use orderColumn for complex sorting. However in your case, ordering by fullname would already work out of the box afaik.

@seewhy17 you can use orderColumn for complex sorting. However in your case, ordering by fullname would already work out of the box afaik.

Well it didn't, I guess the filterColumn method conflicts with an Assessor on the Model which basically does the same thing...I really do not know.
For know I got it to kind of work with by adding a name: lastname to the js, so it filters by lastname and filterColumn method is redundant

Was this page helpful?
0 / 5 - 0 ratings

Related issues

techguydev picture techguydev  ·  3Comments

t0n1zz picture t0n1zz  ·  3Comments

hohuuhau picture hohuuhau  ·  3Comments

SGarridoDev picture SGarridoDev  ·  3Comments

jgatringer picture jgatringer  ·  3Comments