Give your admin the power to print a custom view. No new window, no page jump - just print using AJAX. I've been practicing Backpack fo...
Give your admin the power to print a custom view. No new window, no page jump - just print using AJAX.
I've been practicing Backpack for Laravel in my projects since 2017. All of my projects had something to print - I needed a button inside the table view that would print that entity, but without opening the show view (the default Show view already has a print button). I wanted it to print a custom view, right then and there in the table view, without having to load another page. The best example for this is probably an Invoice that needs its own view, because it needs to look a certain way. So basically… something like this:
It was a fun little feature to build, because I wanted it to happen using AJAX, and the Operation docs don’t cover that exact scenario.
Tabacitu thought it was interesting too, so here’s me explaining how you can do it in Backpack v5 - hopefully it will help you do the same. Let me know what you think in the comments (or in this Github thread).
Note:
Each Entity has its own print layout
Steps:
First of all we need a custom operation, to get integrated with Backpack’s routes & user interface. If you've installed backpack/generators, you can do php artisan backpack:crud-operation BrowserPrint
to generate an operation trait, then modify it as follows:
<?php
namespace App\Http\Controllers\Admin\Operations;
use Illuminate\Support\Facades\Route;
trait BrowserPrintOperation
{
/**
* Define which routes are needed for this operation.
*
* @param string $segment Name of the current entity (singular). Used as first URL segment.
* @param string $routeName Prefix of the route name.
* @param string $controller Name of the current CrudController.
*/
protected function setupBrowserPrintRoutes($segment, $routeName, $controller)
{
Route::get($segment . '/{id}/browserprint', [
'as' => $routeName . '.BrowserPrint',
'uses' => $controller . '@BrowserPrint',
'operation' => 'BrowserPrint',
]);
}
/**
* Add the default settings, buttons, etc that this operation needs.
*/
protected function setupBrowserPrintDefaults()
{
$this->crud->allowAccess('browserprint');
$this->crud->operation('browserprint', function () {
$this->crud->loadDefaultOperationSettingsFromConfig();
});
$this->crud->operation(['list', 'show'], function () {
$this->crud->addButton('line', 'browserprint', 'view', 'crud::buttons.print');
});
}
/**
* Show the view for performing the operation.
*
* @return Response
*/
public function browserprint()
{
$this->crud->hasAccessOrFail('browserprint');
$this->data['crud'] = $this->crud;
$this->data['title'] = $this->crud->getTitle() ?? 'print ' . $this->crud->entity_name;
$this->data['entry'] = $this->crud->getCurrentEntry();
// load the view
return view($this->crud->getCurrentEntry()->print_view, $this->data);
}
}
We need a view layout to be printed. A dummy view with an attribute passed with auto print popup goes as follows.
//resources\views\vendor\backpack\crud\operations\print.blade.php
<html>
<head>
<style>
</style>
</head>
<body>
Custom Print Page {{ $entry->id }}
</body>
<script type="text/javascript">
window.print();
</script>
</html>
A button to display on list & show view to perform print operation.
//resources\views\vendor\backpack\crud\buttons\print.blade.php
@if ($crud->hasAccess('browserprint'))
<a href="{{ url($crud->route.'/'.$entry->getKey().'/browserprint') }}" target="print_frame" class="btn btn-sm btn-link"><i class="la la-print"></i> Print</a>
@endif
Here’s the secret ingredient of the recipe. A hidden iframe where the page gets rendered to be printed. We add it to the view as a widget instead of overriding the view file.
//resources\views\vendor\backpack\base\widgets\iframe.blade.php
<iframe name="print_frame" width=0 height=0 frameborder=0 ></iframe>
Finally we attach the created operation & widget in the CrudController where we want it:
//app\Http\Controllers\Admin\OrderCrudController.php
use \App\Http\Controllers\Admin\Operations\BrowserPrintOperation;
public function setup(){
CRUD::setModel(\App\Models\Order::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/order');
CRUD::setEntityNameStrings('order', 'orders');
$this->crud->operation(['list', 'show'], function () {
$this->data['widgets']['before_content'] = [
[
'type' => 'iframe',
],
];
});
}
Each Entity has its own print layout. So we choose to define it in the model itself. We access this property in defined operation. You can define your custom logic using an accessor if you have distinct views for the same model. I.e; Canceled Invoice, Paid Invoice, Due Invoice etc.
//app/Models/Order.php
public function getPrintViewAttribute(){
return "crud::operations.print";
}
Result:
A print button symmetrically placed on the table view & inside preview:
When clicked, it shows the print popup of the model's custom view:
We learnt about the flexibility of Backpack and created a custom print action. We can use the same principles to define operations such as sms, email, print, import, export. I hope it was helpful :)
Let us know what you think in the comments below. Or tell us about what you have built, that you think is pretty cool, at [email protected] - perhaps you can create an article about that too.
Subscribe to our "Article Digest". We'll send you a list of the new articles, every week, month or quarter - your choice.
What do you think about this?
Wondering what our community has been up to?