All products

Editable Columns

Let you admins make quick edits, right from the table view.

The Whole Fruit Manifesto

This package adds a few editable columns for projects that use Backpack for Laravel v6:

  • editable_text
  • editable_checkbox
  • editable_switch
  • editable_select

When edited, those columns will submit an AJAX request to the controller, so that attribute is updated in the database. The developer is in complete control of the saving process, to make these column as versatile as possible:

  • the saving process can succeed => will show green dot or green text (and/or notification bubble)
  • the saving process can fail => will show red dot or red text (and/or notification bubble)

Backpack Editable Columns Addon

For the editable_text column, as an admin, you'll notice that:

  • the columns that are editable are underlined (dotted)
  • you can click that value to edit it, then
    • Enter saves the value
    • Esc reverts the changes
    • (up arrow) moves one row up (same editable column)
    • (down arrow) moves one row down (same editable column)
    • Tab moves to the next editable input
    • Shift + Tab moves to the previous editable input
    • clicking out of the input keeps the changes, but does not submit them (text becomes greyed out)

For the editable_select:

  • the columns that are editable are underlined (dotted) and there is a dropdown arrow
  • you can click the dropdown to edit the value as you normally do with a select input
  • once the value is selected, it is saved immediately, but you can disable this by setting the save_on_change to false (it will save on only on focus out)
  • the navigation between the editable_select is the same as for the editable_text (Enter, Esc, , , Tab, Shift + Tab)
    • Space or Enter opens the dropdown
  • you can use options attribute to provide the options of the select input, you can directly pass an array or, you can use a closure, in the closure you'll have the entry as an argument (check the examples bellow).
  • Note: when using closures, if you want to have a similar behavior like "select_from_ajax" you can enable the forceReloadAfterUpdate that will redraw the table on update and update the select options given the current entry state. Eg. CRUD::setOperationSetting('forceReloadAfterUpdate', true) in your setupListOperation()

For the editable_checkbox and editable_switch columns, as an admin... you'll notice that it "just works".

Demo

Don't believe how simple it is to use? Go ahead, try it right now, in our online demo.

Installation

Quick Installation

Quick Installation

In your Laravel + Backpack project, run:

php artisan backpack:require:editablecolumns

It will ask you for your token & password - which you get after you purchase this package. If you've purchased previously, you can see your token and password in your Backpack account.

Manual Installation

Alternatively, if the quick installation above doesn't work, you can follow the steps below:

Step 1. Buy access to this package and you'll get an access token. With that token in hand, you should instruct your project to pull in missing packages from our private repository, instead of Packagist:

  • add your token to your project's auth.json file by running composer config http-basic.backpackforlaravel.com [your-token-username] [your-token-password]
  • add the Backpack private repo to your composer.json:
"repositories": [
    {
        "type": "composer",
        "url": "https://repo.backpackforlaravel.com/"
    }
],

Step 2. In your project, via command line:

composer require backpack/editable-columns

Usage

Step 1. Inside your ProductCrudController (for example), use this new operation we've provided:

class ProductCrudController extends CrudController
{
    use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
    use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation;
    use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation;
    use \Backpack\CRUD\app\Http\Controllers\Operations\CloneOperation;
    use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
+   use \Backpack\EditableColumns\Http\Controllers\Operations\MinorUpdateOperation;

    public function setup()
    {
        CRUD::setModel(\App\Models\Product::class);
        CRUD::setRoute(config('backpack.base.route_prefix').'/product');
        CRUD::setEntityNameStrings('product', 'products');
    }

Step 2. In your ListOperation, instead of using text, number, check, select_from_array columns, use the columns this package provides, if you want them editable:

public function setupListOperation() 
{
    // editable_text
    CRUD::addColumn([
        'name'             => 'price',
        'type'             => 'editable_text',
        'label'            => 'Price',

        // Optionals
        'underlined'       => true, // show a dotted line under the editable column for differentiation? default: true
        'min_width'        => '120px', // how wide should the column be?
        'select_on_click'  => false, // select the entire text on click? default: false
        'save_on_focusout' => false, // if user clicks out, the value should be saved (instead of greyed out)
        'on_error' => [
            'text_color'          => '#df4759', // set a custom text color instead of the red
            'text_color_duration' => 0, // how long (in milliseconds) should the text stay that color (0 for infinite, aka until page refresh)
            'text_value_undo'     => false, // set text to the original value (user will lose the value that was recently input)
        ],
        'on_success' => [
            'text_color'          => '#42ba96', // set a custom text color instead of the green
            'text_color_duration' => 3000, // how long (in milliseconds) should the text stay that color (0 for infinite, aka until page refresh)
        ],
        'auto_update_row' => true, // update related columns in same row, after the AJAX call?
    ]);

    // editable_checkbox
    CRUD::addColumn([
        'name'  => 'agreed',
        'label' => 'Agreed',
        'type'  => 'editable_checkbox',

        // Optionals
        'underlined' => true, // show a dotted line under the editable column for differentiation? default: true
        'on_error' => [
            'status_color'          => '#df4759', // set a custom text color instead of the red
            'status_color_duration' => 0, // how long (in milliseconds) should the text stay that color (0 for infinite, aka until page refresh)
            'switch_value_undo'     => false, // set checkbox to the original value (user will lose the value that was recently input)
        ],
        'on_success' => [
            'status_color'          => '#42ba96', // set a custom text color instead of the green
            'status_color_duration' => 3000, // how long (in milliseconds) should the text stay that color (0 for infinite, aka until page refresh)
        ],
        'auto_update_row' => true, // update related columns in same row, after the AJAX call?
    ]);

    // editable_switch
    CRUD::addColumn([
        'name'  => 'agreed',
        'label' => 'Agreed',
        'type'  => 'editable_switch',

        // Optionals
        // All the options available on editable_checkbox are available here too, plus;
        'color'   => 'success',
        'onLabel' => '✓',
        'offLabel' => '✕',
    ]);

    // editable_select
    CRUD::addColumn([
        'name'    => 'categories',
        'label'   => 'Categories',
        'type'    => 'editable_select',
        'options' => \App\Models\Category::all()->pluck('name', 'id')->toArray(),
        // or
        'options' => (function ($entry) {
            return \App\Models\Category::whereDate('created_at', '<=', $entry->created_at)
                ->pluck('name', 'id')->toArray(),
        }),
        // or
        'options' => [
            '1' => 'One',
            '2' => 'Two',
            '3' => 'Three',
        ],

        // Optionals
        'underlined'       => true, // show a dotted line under the editable column for differentiation? default: true
        'save_on_focusout' => true, // if user clicks out, the value should be saved (instead of greyed out)
        'save_on_change'   => true,
        'on_error' => [
            'text_color'          => '#df4759', // set a custom text color instead of the red
            'text_color_duration' => 0, // how long (in milliseconds) should the text stay that color (0 for infinite, aka until page refresh)
            'text_value_undo'     => false, // set text to the original value (user will lose the value that was recently input)
        ],
        'on_success' => [
            'text_color'          => '#42ba96', // set a custom text color instead of the green
            'text_color_duration' => 3000, // how long (in milliseconds) should the text stay that color (0 for infinite, aka until page refresh)
        ],
        'auto_update_row' => true, // update related columns in same row, after the AJAX call?
    ]);
}

Step 3.A. Then inside setupMinorUpdateOperation(), define what FormRequest you want to use for validation. You can use the exact same FormRequest that you've used in your Create/Update operations, because MinorUpdate will only consider the validation rule for the currently edited attribute (and ignore everything else). So in most cases you just need to do:

protected function setupMinorUpdateOperation()
{
    $this->crud->setValidation(StoreRequest::class);
}

Step 3.B. Alternatively, if you don't want to use a FormRequest for validation, but instead want to write some custom validation logic, or you need to modify the saving process, you can easily do that too. Just override the methods saveMinorUpdateFormValidation() (to override the validation), and saveMinorUpdateEntry() (to override the saving process). This methods are used by saveMinorUpdate() which you may also override although it's not really necessary. The example below shows how to confirm/deny the edit. Modify it so it fits your project, it's in your control.

public function saveMinorUpdateFormValidation()
{
    // validation example for the "price"
    // note that this is just an example, you may do this with the FormRequest
    if (request('attribute') === 'price' && !is_numeric(request('value'))) {
        throw ValidationException::withMessages([
            'price' => ['The price has to be a number.'],
        ]);
    }
}
public function saveMinorUpdateEntry()
{
    // Save the minor update
    $entry = $this->crud->getModel()->find(request('id'));
    $entry->{request('attribute')} = request('value');
    
    // Perform specific logic
    $entry->status = 'draft';

    $entry->save();

    return $entry->refresh();
}

Allowing null on the select column

If your column is nullable on database and you want to allow your users to send an empty selection you should add the "empty option" yourself when providing the select options.

CRUD::addColumn([
        'name'    => 'categories',
        'label'   => 'Categories',
        'type'    => 'editable_select',
        'options' => array_merge(['' => 'No category'], \App\Models\Category::all()->pluck('name', 'id')->toArray()),
        // or
        'options' => [
            ''  => 'No Category',
            '1' => 'One',
            '2' => 'Two',
            '3' => 'Three',
        ],
    ]);

Search Logic for Editable Columns

Editable columns need to know what search logic to use. We are working on a way to avoid this step, but as of now, you should manually define the searchLogic that should be applied for each column type. Example:

CRUD::addColumn([
        'name'             => 'email',
        'type'             => 'editable_text',
        'label'            => 'Email',
        
        'searchLogic'      => 'text', // this will tell backpack to use the "text" column search logic.
        
        // or alternatively provide your own custom search logic in a closure as you would do for any other column
        'searchLogic'      => function ($query, $column, $searchTerm) {
                $query->orWhere('email', 'like', '%'.$searchTerm.'%');
            });
        
    ]);

For text based columns you can just tell Backpack to use the text column searchLogic as shown in the example above.

At the moment the other columns don't have any default searchLogic so you should write your own if needed.

| Editable Column | Apply Search Logic From Column | |:-:|:-:| | editable_text | text | | editable_checkbox | write your custom | | editable_switch | write your custom | | editable_select | write your custom |

Reloading the table after column is updated

If you want to reload the table after a column is updated you can use the forceReloadAfterUpdate setting. This will redraw the whole table on update Eg. CRUD::setOperationSetting('forceReloadAfterUpdate', true) in your setupListOperation()

Alternatively you can just trigger full table the reload if some specific columns change. For That you can set the forceReloadAfterUpdate to an array of column names, or a single string of a column name, that should trigger the reload. Eg. CRUD::setOperationSetting('forceReloadAfterUpdate', ['price', 'status']) or CRUD::setOperationSetting('forceReloadAfterUpdate', 'status') in your setupListOperation().

Security

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

Credits

Big thanks to Kevin Ohashi of Review Signal and NameBio.com, who has sponsored building this addon. If you need a Backpack addon too, reach out, we love to build them. Created by:

License

This project was released under EULA, so you can install it on top of any Backpack & Laravel project. Please see the license file for more information.

Package Access

You don't currently have access to this package. To gain access, go ahead and purchase it. You'll get:

Next 12 months
  • download or install using Composer;
  • all updates (major, minor and patch);
After 12 months
  • can still access all versions and updates you paid;
  • can still install using Composer;
  • no new versions or updates;
Buy for 99 EUR