4

I have spent a fair few days researching datatables and yajra package, That said I am no closer to getting the result I need and would greatly appreciate a helping hand on this one if anyone with more knowledge than my novice approach!

To help explain better I have attached two images, First image is of an application that already has this implemented and second is a quick mock I have thrown up to show the difference.


The desired outcome I am hoping to achieve... enter image description here


The present view I have...enter image description here


I'm basically trying to add custom html to each column that requires the functionality.. I have managed to achieve some slight success by returning a custom array like so:

foreach ($tasks as $task) {
    $checkBox = '<div class="checkbox"><input type="checkbox" value="63"><label></label></div>';
    $taskPriority = '<span class="text-info inline-block">Medium</span>';
            ... so on ...
    $row = array(
        $checkBox,
        $taskPriority,
        ... so on ...
    );
    $rows[] = $row;
}
$list['data'] = $rows;
return $list;

While this works I would not say its the best approach and one imagines there is some what a better and more elegant way of doing this?

I understand yajra has the addColumn and editColumn methods, I have used these to add an action column as that is the only one that seems to render any html, Any other method other than addColumn('action', 'blah blah') seems not to want to render the html and instead displays it as raw text in the row.

Just in case this is to help anyone, here is the Ajax call made to get the table data.

$('#taskstable').DataTable({
    "processing": true,
    "retrieve": true,
    "serverSide": true,
    'paginate': true,
    'searchDelay': 700,
    "bDeferRender": true,
    "responsive": true,
    "autoWidth": false,
    "pageLength": 5,
    "lengthMenu": [[5, 10, 25, 50, 100], [5, 10, 25, 50, 100]],
    ajax: '/tasks/get-tasks'
});

Hopefully someone can help relieve the stress of being a novice! Thanks.

3 Answers 3

3

bro i can you some idea this may help you to get your desired result. Controller:

public function index(Request $request)
    {
        $data = [];
        $data['page_title'] = trans($this->trans_path . 'general.page.index.page-title');
        $data['show_modal'] = false;
        $data['trans_path'] = $this->trans_path;
        if ($request->get('add') && $request->get('add') == "true") {
            $data['show_modal'] = true;
        }

        // TODO: Confirm this logic
        //count no. of promoter admin
        $data['promoter'] = User::where('user_type', AclHelper::getUsersTypeKey('promoter-admin'))->count();

        // for mapping policy
        $data['admin_user_model'] = new AdminUser();

        //generate add Button
        $data['add_btn_html'] = view($this->loadDefaultVars($this->view_path . '.partials._promoter_add_button'))->render();
        $data['assignable_user_roles'] = $this->getAssignableRolesByAuthUser();

        return view($this->loadDefaultVars($this->view_path . '.index'), compact('data'));
    }

    public function search(Request $request)
    {

        $data = [];
        $columns = ['rud.*', 'us.first_name as promoter_first_name', 'us.last_name as promoter_last_name', 'users.email', 'users.username',
            'r.name', 'r.display_name', 'rud.created_by', 'rud.promoter_id', 'users.enabled'];
        $users = $this->getUserListJoinQuery($columns)
            ->leftJoin('role_users_details as us', 'rud.promoter_id', '=', 'us.id')
            ->groupBy('users.id');

        if (in_array(AclHelper::getUsersTypeKey('super-admin'), AclHelper::getUserRoles(), 1) ||
            in_array(AclHelper::getUsersTypeKey('support-admin'), AclHelper::getUserRoles(), 1)
        ) {
            $users->where('users.id', '!=', auth()->user()->id);
            $data['users'] = $users->get();
        } else {

            if (in_array(AclHelper::getUsersTypeKey('promoter-admin'), AclHelper::getUserRoles(), 1))
                $data['users'] = $users->where('rud.promoter_id', Auth::user()->id)->get();
            elseif (in_array(AclHelper::getUsersTypeKey('promoter-editor'), AclHelper::getUserRoles(), 1)) {
                $promoter_id = Auth::user()->userDetail->promoter_id;
                $users->where('r.name', '!=', AclHelper::getUsersTypeKey('promoter-editor'));
                $data['users'] = $users->where('rud.promoter_id', $promoter_id)->get();
            } else {
                return response('Unauthorized request made.', 401);
            }
        }

        return Datatables::of($data['users'])
            ->editColumn('user_id', function ($users) {
                $data = view($this->loadDefaultVars($this->view_path . '.partials._action_fields'), compact('users'))->render();
                return $data;
            })
            ->editColumn('profile_image', function ($users) {
                if (!isset($users->profile_image)) {
                    return "";
                }
                return '<img src="' . asset(config('neptrox.admin_user_path.thumbnail') . $users->profile_image) .
                '" alt="' . $users->first_name . '" style="height: 40px;" >';
            })
            ->editColumn('name', function ($users) {
                return $users->first_name . ' ' . $users->middle_name . ' ' . $users->last_name;
            })
            ->editColumn('gender', function ($users) {
                if ($users->gender === 'male')
                    return 'Male';
                elseif ($users->gender === 'female')
                    return 'Female';
                else
                    return 'Other';
            })
            ->editColumn('user_type', function ($users) {
//                return $users->pivot->display_name;
                return config('neptrox.admin-users-roles.' . $users->name . '.title');
            })
            ->editColumn('promoter', function ($users) {
                return $users->promoter_first_name . ' ' . $users->promoter_last_name;
            })
            ->editColumn('status', function ($users) {
                if ($users->enabled === 1) {
                    return "<span class='text-success'> " .
                    '<i class="fa fa-check-circle-o text-info"></i>' .
                    "</span>";
                }
                return "<span class='text-danger'>" .
                '<i class="fa fa-ban text-danger"></i>' .
                "</span>";
            })
            ->make(true);

    }

jquery Scripts

<script src="https://cdn.datatables.net/1.10.12/js/jquery.dataTables.min.js" type="text/javascript"></script>
<script>

    (function (options) {

        var route_url = options.dataTableConfigVariable.route_url;
        var columns = options.dataTableConfigVariable.columns;
        var order = options.dataTableConfigVariable.orderColumn;
        if (order == 'undefined' || order == null || order == "") {
            order = 1;
        }
        var config = {
            "dom": '<t>' +
            '<"card-footer card-pagination"<"row"<"col-md-8"p><"col-md-4 form-design1 right"l>>>',
            "oLanguage": {
                "sLengthMenu": " _MENU_ ",
                "sSearchPlaceholder": "Search",
                "oPaginate": {
                    "sNext": "<span aria-hidden='true'>»</span><span class='sr-only'>Next</span>",
                    "sPrevious": "<span aria-hidden='true'>«</span><span class='sr-only'>Previous</span>"
                },
            },
            processing: true,
            serverSide: true,
            ajax: {
                type: 'POST',
                url: route_url.dataTable_url,
                data: {
                    _token: $('meta[name=csrf-token]').attr("content")
                }
            },
            columns: columns,
            'order': [[order, 'asc']]
        };

        //initialize dataTables
        var table = $('table.table').DataTable(config);

        $('#searchField').keyup(function(){
            table.search($(this).val()).draw() ;
        });


        //Enables or disables the performer and reload the ajax after success
        $('body').on('click', '.enableDisable', function (e) {
            e.preventDefault();
            var url = $(this).attr('href');
            $.ajax({
                type: 'GET',
                url: url,
                success: function (response) {
                    table.ajax.reload(null, false);
                }
            });
        });

        //toggle all checkbox checked or unchecked
        $('body').on('click', 'input[name="checkAll"]', function () {
            var checkBoxes = $("input[name=checkbox\\[\\]]");
            checkBoxes.prop("checked", $(this).prop("checked"));
        });

        //enable selected performers
        $('body').on('click', '#enable', function (e) {
            var url = route_url.enableAll;
            enableDisablePerformer(e, url);
        });

        //disable selected performers
        $('body').on('click', '#disable', function (e) {
            var url = route_url.disableAll;
            enableDisablePerformer(e, url);
        });

        function enableDisablePerformer(e, url) {
            e.preventDefault();
            var formData = $('input[name^=checkbox]');
            var data = {};
            formData.each(function (index) {
                if ($(this).is(':checked')) {
                    data[index] = $(this).val();
                }
            });
            $.ajax({
                type: 'POST',
                url: url,
                data: {
                    _token: $('meta[name=csrf-token]').attr("content"),
                    id: data
                },
                success: function (response) {
                    if (response == 'ok') {
                        table.ajax.reload(null, false);
                        $('body').find('input[name="checkAll"]').prop('checked', false);
                    }
                }
            });
        }


        //Delete confirmation popup
        $('body').on('click', '.try-sweet-warningConfirm', function () {
            var id = $(this).attr('id');
            swal({
                title: "{{ trans($trans_path.'general.delete.sure') }}",
                text: "{{ trans($trans_path.'general.delete.message') }}",
                type: "warning",
                showCancelButton: true,
                confirmButtonColor: "{{ trans($trans_path.'general.delete.confirmButtonColor') }}",
                confirmButtonText: "{{ trans('general.button.delete') }}",
                cancelButtonText: "{{ trans('general.button.cancel') }}",
                closeOnConfirm: true
            }, function (isConfirm) {
                if (isConfirm) {
                    $.ajax({
                        type: 'POST',
                        url: route_url.delete,
                        data: {
                            _token: $('meta[name=csrf-token]').attr("content"),
                            id: id
                        },
                        success: function (response) {
                            table.row($(this).closest('tr')).remove().draw();
                            if (response == 'ok') {
                                swal({
                                    title: "{{ trans($trans_path.'general.status.delete') }}",
                                    text: "{{ trans($trans_path.'general.status.deleted') }}",
                                    type: "success",
                                    timer: 2000,
                                    confirmButtonColor: "{{ trans($trans_path.'general.delete.confirmButtonColor') }}"
                                });
                            }
                        }
                    });

                }
            });
        });

        //Delete bulk confirmation popup
        $('body').on('click', '#delete', function () {
            swal({
                title: "{{ trans($trans_path.'general.delete.sure') }}",
                text: "{{ trans($trans_path.'general.delete.message') }}",
                type: "warning",
                showCancelButton: true,
                confirmButtonColor: "{{ trans($trans_path.'general.delete.confirmButtonColor') }}",
                confirmButtonText: "{{ trans('general.button.delete') }}",
                cancelButtonText: "{{ trans('general.button.cancel') }}",
                closeOnConfirm: true
            }, function (isConfirm) {
                if (isConfirm) {
                    var url =route_url.delete;
                    deleteBulkPerformer(url);
                    $('body').find('input[name="checkAll"]').prop('checked', false);
                    swal({
                        title: "{{ trans($trans_path.'general.status.delete') }}",
                        text: "{{ trans($trans_path.'general.status.deleted') }}",
                        type: "success",
                        timer: 2000,
                        confirmButtonColor: "{{ trans($trans_path.'general.delete.confirmButtonColor') }}"
                    });
                }
            });
        });

        function deleteBulkPerformer(url){
            var formData = $('input[name^=checkbox]');

            var data = {};
            formData.each(function (index) {
                if ($(this).is(':checked')) {
                    data[index] = $(this).val();
                }
            });
            $.ajax({
                type: 'POST',
                url: url,
                data: {
                    _token: $('meta[name=csrf-token]').attr("content"),
                    id: data,
                    bulk: 'bulk'
                },
                success: function (response) {
                    if (response == 'ok') {
                        table.row($(this).closest('tr')).remove().draw();
                    }
                }
            });
        }

    })({dataTableConfigVariable:dataTableConfigVariable});

</script>

View Page

 <script>
        var dataTableConfigVariable = {
            route_url: {
                dataTable_url:  '{{route("admin.admin_users.search")}}',
                enableAll: '{{route("admin.admin_users.enableAll")}}',
                disableAll: '{{route("admin.admin_users.disableAll")}}',
                delete: '{{route("admin.admin_users.delete")}}'
            },
            columns: [
                {data: 'user_id', name: 'user_id', orderable: false, searchable: false},
                {data: 'profile_image', name: 'profile_image', orderable: false, searchable: false},
                {data: 'name', name: 'name'},
                {data: 'user_code', name: 'user_code', orderable: false},
                {data: 'email', name: 'email'},
                {data: 'username', name: 'username'},
                {data: 'gender', name: 'gender'},
                {data: 'user_type', name: 'user_type'},
                {data: 'promoter', name: 'promoter', orderable: false, searchable: false},
                {data: 'status', name: 'status', orderable: false, searchable: false},
            ],
            orderColumn: 2
        };
    </script>
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for taking time out to post your code, I will have a look at it very soon as on mobile decide at the moment so I am unable to see the whole post but look forward to reading your solution :) thanks
0

The easiest approach I have found as of the time I post this answer is as follows, That being said I am sure this is not the best approach to take and maybe in time to come someone with more experience than myself will be able to post a better solution.


In my project I am using a specific package called Laravel Collective that can be found: ...here..

Using this package gives you access to a helper class and facade. With some slight modification that is specific to my application i have been able to make great use of this package.

One similar approach would be to do this:

public function getTasks()
{
    $tasks = $this->taskInterface->model()->all();
    return $this->datatables->collection($tasks)
        ->editColumn('name', function ($model) {
            return HtmlFacade::link("admin/tasks/{$model->id}", $model->name);
        })
        ->addColumn('action', function($query) {
            return view('backend.global.tables.actions.all-tasks-actions', compact('query'));
        })
        ->make(true);
}

Note

when using the return HtmlFacade::link(); method this will return html that gets rendered on the data table, A full list of methods can be found by looking at the documentation or in my case going through the class its self and seeing the source code gave me a better understanding of how their package worked, Not only that but it gives the ability to add further methods to the class and that's how I have come to get the outcome I required.

I am not going to post all the custom classes as I don't think it is too relevant to helping anyone in the future as the methods I have added or very similar to what the package comes with out of the box, the only difference is to allow for onclick JavaScript events and incline CSS.

The moral of this answer is to let anyone else in a similar position to myself know that if you are already using this package then its possible you do not need to cast all rows to arrays manually just to pass custom html to the view and I no longer need to do this:

 $rows = [];
 $checkBox = '<div class="checkbox"><input type="checkbox" value="63"><label></label></div>';
 $taskPriority = '<span class="text-info inline-block">Medium</span>';
 ect... As seen in original post..

instead you can pass custom attributes, classes and build up from the laravel collective package, Here is the link method laravel collective comes with that can be a building block to adding custom methods to their package.

public function link($url, $title = null, $attributes = [], $secure = null, $escape = true)
{
    $url = $this->url->to($url, [], $secure);

    if (is_null($title) || $title === false) {
        $title = $url;
    }

    if ($escape) {
        $title = $this->entities($title);
    }

    return $this->toHtmlString('<a href="' . $url . '"' . $this->attributes($attributes) . '>' . $title . '</a>');
}

That should give people an idea of how you can easily modify this Html Builder to your requirements, As I said I am sure this is not the best and most elegant want of achieving the same if not better outcome so I will leave the question open for future solutions I just thought I would share my solution.

Comments

0

You may find the answer in the below code. I have shared the main index function and the view file.

Controller Code:

 public function index(Request $request)
{
    if ($request->ajax()) {
        $data = DB::table('issue_details as id')
            ->join('collection_batch as cb','cb.issue_no','=','id.issue_no')
            ->join('customers as c','c.id','=','cb.customer_id')
            ->groupBy(['id.issue_no','c.name','cb.collection_amount','cb.balance_amount','cb.discount_amount'])
            ->get(['id.issue_no','c.name as customer_name','cb.collection_amount as paid_amount','cb.balance_amount as due_amount',
                'cb.discount_amount',
                DB::raw('sum(id.order_quantity-id.returned_quantity) as total_order_quantity'),
                DB::raw('sum(id.total_price) as total_order_price')]);

        return Datatables::of($data)
            ->addIndexColumn()
            ->addColumn('action', function($row){
                $buttons='';
                $buttons .= '<a href="'.route('collections.show', $row->issue_no).'"> <button class="btn btn-warning btn-xs">Show</button> </a>';
                $buttons .= '<button '.($row->due_amount==0 ? 'disabled style="display:none"' : "").' class="btn btn-info btn-xs" id="'.$row->issue_no.'" onclick="collectionEdit(this.id)">Edit </button>';
                return $buttons;
            })
            ->rawColumns(['action'])
            ->make(true);
    }
    return view('collection.index');
}

View File Code:

<div class="content-wrapper">
<div class="content-header">
    <div class="container-fluid">
        <div class="row mb-2">
            <div class="col-sm-6">
                <h1 class="m-0">Collection History</h1>
            </div>
            <div class="col-sm-6">
                <ol class="breadcrumb float-sm-right">
                    <li class="breadcrumb-item"><a href="{{ route('home') }}">Home</a></li>
                    <li class="breadcrumb-item"><a href="{{ route('collections') }}">Collection History</a></li>
                </ol>
            </div>
        </div>
    </div>
</div>

<section class="content">
    <div class="container-fluid">
        <div class="row">
            <div class="col-12">
                <div class="card">
                    <div class="card-header">
                    </div>
                    <div class="card-body">
                        <table id="datatable" class="table table-bordered table-striped">
                            <thead>
                            <tr>
                                <th>Sl No</th>
                                <th>Invoice No</th>
                                <th>Customer</th>
                                <th>Total Price</th>
                                <th>Paid</th>
                                <th>Due</th>
                                <th>Discount</th>
                                <th>Action</th>
                            </tr>
                            </thead>
                            <tbody>

                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>
    </div>
</section>

**JS Part:**
<script type="text/javascript">
        $(function() {
            var i = 1;
            var table = $('#datatable').DataTable({
                processing: true,
                serverSide: true,
                ajax: "{{ route('collections') }}",
                columns: [{
                    "render": function() {
                        return i++;
                    }
                },
                    {
                        data: 'issue_no',
                        name: 'issue_no'
                    },
                    {
                        data: 'customer_name',
                        name: 'customer_name'
                    },
                    {
                        data: 'total_order_price',
                        name: 'total_order_price'
                    },
                    {
                        data: 'paid_amount',
                        name: 'paid_amount'
                    },
                    {
                        data: 'due_amount',
                        name: 'due_amount'
                    },
                    {
                        data: 'discount_amount',
                        name: 'discount_amount'
                    },
                    {
                        data: 'action',
                        name: 'action',
                        orderable: false,
                        searchable: false
                    }
                ],
                createdRow: function ( row, data, index ) {
                    if (data['due_amount'] > 0) {
                        $('td', row).eq(4).css('background-color', '#f4511e','color','#ffffff');
                        $('td', row).eq(4).css('color','#ffffff');
                    } else {
                    }
                    $('td', row).eq(3).addClass('text-right');
                    $('td', row).eq(4).addClass('text-right');
                    $('td', row).eq(5).addClass('text-right');
                    $('td', row).eq(6).addClass('text-right');
                }
            });
        });
    </script>

From the last section, you can customize the code as your desired format

2 Comments

What does You may find the answer in the below code mean? Is this an answer or it's not?
It is the answer. I have implement it in my project.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.