Having a grid in your custom Magento 2 module, more often than not means you will have mass actions. Below, we will see how we can add mass actions to our custom grid in Magento 2.

For those of you who do not know, mass actions are actions available in the grid which can be applied to multiple grid items at once, instead of having to apply them to each item individually.

For example, changing status of the grid line items. When changing status you may want to change the items of batch of items instead of just a single item. Mass actions come in handy when you want to do this. It allows you to select the items you want the action to apply to, and then apply the mass action, which will filter the grid items and apply the action to each of the selected items.

Follow the steps below to add mass actions to your admin grid:

I will assume you’ve setup your UI component grid and you have a file (say) view/adminhtml/ui_component/*_listing.xml.

To add the mass action block to the ui component xml, you edit the file and add the <massaction>...</massaction> xml block inside the <listingToolbar>..</listingToolbar> of your grid as shown below:

Your <listingToolbar /> block might look something like this:

<listingToolbar name="listing_top">
    <settings>
        <sticky>true</sticky>
    </settings>
    <bookmark name="bookmarks"/>
    <columnsControls name="columns_controls"/>
    <filters name="listing_filters"/>
    <paging name="listing_paging"/>
    ...
</listingToolbar>

You need to <massaction /> block inside the <listingToolbar /> block:

<listingToolbar name="listing_top">
    <settings>
        <sticky>true</sticky>
    </settings>
    <bookmark name="bookmarks"/>
    <columnsControls name="columns_controls"/>
    <filters name="listing_filters"/>
    <paging name="listing_paging"/>
    <massaction name="listing_massaction">
        <action name="update_status">
            <settings>
                <type>update_status</type>
                <label translate="true">Update status</label>
                <actions class="{Namespace}\{Module}\Ui\Component\MassAction\Status\Options"/>
            </settings>
        </action>
        <action name="delete">
            <settings>
                <confirm>
                    <message translate="true">Are you sure to delete selected items?</message>
                    <title translate="true">Delete items</title>
                </confirm>
                <url path="{frontname}/{controller}/{action}"/>
                <type>delete</type>
                <label translate="true">Delete</label>
            </settings>
        </action>
        ...
    </massaction>
    ...
</listingToolbar>

The <action>...</action> block with a unique name adds an action to the grid. You can define multiple actions pointing to multiple controller actions to your grid.

As you can see above, in our XML, we have defined 2 actions with different settings. The most important one being the first one uses an <actions /> setting block and the second one uses <url />.

The difference between the 2 is that, <actions /> groups multiple related actions under a single mass action. In our case, status update with 3 options (active, inactive and pending approval). When you select the mass action you will be provided with a list of 3 options to change the status of your selected grid items to one of them.

Note: Make sure the <actions class="{Your full class name}" ... /> is a valid class.

Following is a sample actions class:

<?php

namespace {Namespace}\{Module\Ui\Component\MassAction\Status;

use Magento\Framework\Phrase;
use Magento\Framework\UrlInterface;

class Options implements \JsonSerializable
{
    /**
     * @var array
     */
    protected $options;

    /**
     * Additional options params
     *
     * @var array
     */
    protected $data;

    /**
     * @var UrlInterface
     */
    protected $urlBuilder;

    /**
     * Base URL for subactions
     *
     * @var string
     */
    protected $urlPath;

    /**
     * Param name for subactions
     *
     * @var string
     */
    protected $paramName;

    /**
     * Additional params for subactions
     *
     * @var array
     */
    protected $additionalData = [];

    /**
     * Constructor
     *
     * @param UrlInterface $urlBuilder
     * @param array $data
     */
    public function __construct(
        UrlInterface $urlBuilder,
        array $data = []
    ) {
        $this->data = $data;
        $this->urlBuilder = $urlBuilder;
    }

    /**
     * Get action options
     *
     * @return array
     */
    public function jsonSerialize()
    {
        if ($this->options === null) {
            $options = [[
                'value' => 'pending',
                'label' => 'Pending approval'
            ], [
                'value' => 'active',
                'label' => 'Active'
            ], [
                'value' => 'inactive',
                'label' => 'Inactive'
            ]];

            // Prepares additional settings passed using XML
            $this->prepareData();

            // Applies URL and param name for each sub-action, and any other additional data 
            foreach ($options as $optionCode) {
                $this->options[$optionCode['value']] = [
                    'type' => 'your_action+' . $optionCode['value'],
                    'label' => __($optionCode['label']),
                ];

                if ($this->urlPath && $this->paramName) {
                    $this->options[$optionCode['value']]['url'] = $this->urlBuilder->getUrl(
                        $this->urlPath,
                        [$this->paramName => $optionCode['value']]
                    );
                }

                $this->options[$optionCode['value']] = array_merge_recursive(
                    $this->options[$optionCode['value']],
                    $this->additionalData
                );
            }

            $this->options = array_values($this->options);
        }

        return $this->options;
    }

    /**
     * Prepare addition data for subactions
     *
     * @return void
     */
    protected function prepareData()
    {
        foreach ($this->data as $key => $value) {
            switch ($key) {
                case 'urlPath':
                    $this->urlPath = $value;
                    break;
                case 'paramName':
                    $this->paramName = $value;
                    break;
                case 'confirm':
                    foreach ($value as $messageName => $message) {
                        $this->additionalData[$key][$messageName] = (string) new Phrase($message);
                    }
                    break;
                default:
                    $this->additionalData[$key] = $value;
                    break;
            }
        }
    }
}

As for <url />, it defines a single action (in our case, delete), and when the mass action is selected, the selected items list is sent posted to the URL path which then acts accordingly (in our case, delete the item if it exists).

Note: Make sure the <url path="{your path}" ... /> is a valid controller action.

Finally, your mass action controller:

<?php

namespace {Namespace}\{Module}\Controller\Adminhtml\{ControllerName};

use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Ui\Component\MassAction\Filter;
use Magento\Framework\Controller\Result\JsonFactory;
use {Namespace}\{Module}\Model\ResourceModel\{ModelName}\CollectionFactory;

class {ActionName} extends Action
{
    /**
     * @var Filter
     */
    private $filter;

    /**
     * @var CollectionFactory
     */
    private $collectionFactory;

    /**
     * @param Context     $context
     * @param JsonFactory $resultJsonFactory
     */
    public function __construct(
        Context $context,
        Filter $filter,
        CollectionFactory $collectionFactory
    ) {
        $this->filter = $filter;
        $this->collectionFactory = $collectionFactory;

        parent::__construct($context);
    }

    /**
     * Execute action.
     *
     * @return \Magento\Backend\Model\View\Result\Redirect
     *
     * @throws \Magento\Framework\Exception\LocalizedException|\Exception
     */
    public function execute()
    {
        /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
        $resultRedirect = $this->resultRedirectFactory->create();

        try {
            $collection = $this->filter->getCollection($this->collectionFactory->create());

            $done = 0;
            foreach ($collection as $item) {
                // Your action here.
                $item->delete();
                ++$done;
            }

            if ($done) {
                $this->messageManager->addSuccess(__('A total of %1 record(s) were modified.', $done));
            }
        } catch (\Exception $e) {
            $this->messageManager->addError($e->getMessage());
        }

        return $resultRedirect->setUrl($this->_redirect->getRefererUrl());
    }

    /**
     * @return bool
     */
    protected function _isAllowed()
    {
        return $this->_authorization->isAllowed('{Namespace}_{Module}::mass_{action}');
    }
}
Live chat: cookie consent required

Copyright © Hungersoft 2019

· Terms & Conditions · Privacy policy