How to create a Print operation

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...

Karan Datwani
Karan Datwani
Share:

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).

What we’ll be building:

Note:

Each Entity has its own print layout

Steps:

  1. Create Print Operation
  2. Create Print Operation View
  3. Create Print Button
  4. Create Hidden Iframe Widget
  5. Setup Operation & Widget in Controller
  6. Define Print View in Model

Code:

1) Create Print Operation

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);
   }
}

2) Create Print Operation View

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>

3) Create Print Button

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

4) Create Hidden Iframe Widget

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>

5) Setup Operation & Widget in Controller

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',
               ],
           ];
       });
   }

6) Define Print View in Model.

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:

Summary

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.

Want to receive more articles like this?

Subscribe to our "Article Digest". We'll send you a list of the new articles, every week, month or quarter - your choice.

Reactions & Comments

What do you think about this?

Latest Articles

Wondering what our community has been up to?