4

I've created a grid via ui component with a mass action. I've also added a selections column so when the user click on one or more checkboxes, the items in the grid get selected and the mass action can be called on those items.

This work if the user selects only some records from the list, but if the user selects all the items by the action dropdown "select all", then the mass action cannot work.

This is because different parameters are used: - when the user checks the boxes individually, then the "selected" parameter is passed to my controller with the id selected - when the user chooses "select all", no "selected" parameter is passed. Instead, there is a parameter "excluded" false and no ids are passed to my controller.

Magento doesn't need the ids when "select all" is chosen because the mass action simply loads the collection. My problem is that my grid is not related to a table, so I cannot call any model/collection. I have a custom data provider that gets the data from an external source and displays the data in the grid.

Calling the external data all over again in the mass action controller is far more expensive than simply passing the ids, so simulating the magento way of reloading the collection is not a desirable option. The best thing in my opinion would be to pass the "selected" parameter also when all items are selected with the "select all" dropdown option.

Is there a way to achive this?

My code is pretty standard:

  • the mass action and the grid is build via ui component listing:
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
...
<listingToolbar name="listing_top">
  <massaction name="listing_massaction">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="selectProvider" xsi:type="string">my_provider.ids</item>
                    <item name="indexField" xsi:type="string">id</item>
                </item>
            </argument>
            <action name="massaction_name">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="type" xsi:type="string">massaction_name</item>
                        <item name="label" xsi:type="string" translate="true">Mass Action Name</item>
                        <item name="url" xsi:type="url" path="route/controller/path"/>
                        <item name="confirm" xsi:type="array">
                            <item name="title" xsi:type="string" translate="true">Title</item>
                            <item name="message" xsi:type="string" translate="true">Are you sure?</item>
                        </item>
                    </item>
                </argument>
            </action>
        </massaction>
...
<columns name="my_provider_columns">
   <column name="ids">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="indexField" xsi:type="string">id</item>
                    <item name="dataType" xsi:type="string">select</item>
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/onoff</item>
                </item>
            </argument>
        </column>
...
  • the controller retrieves the request parameters:
...
class Path extends Action implements HttpGetActionInterface, HttpPostActionInterface
...
public function execute() {
  $params = $this->getRequest()->getParams();
}
...

As I mentioned, $params returns an array "selected" with the ids or a flag set to false if "selectAll" was used for the selection:

array (
  'selected' => 
  array (
    0 => '505928',
...
array (
  'excluded' => 'false'
...

But I need the "selected" array also when the selectAll option is used. Is there a way to get it?

3
  • Were you able to solve this issue? – Eric Libay Jun 4 '20 at 22:14
  • @Lou Nik did you get the solution for this? – jafar pinjar Mar 25 at 11:16
  • @jafarpinjar hi, I haven't been able to find a real solution, sorry, what I did was to remove the "select all" option from the dropdown and add a separate button. This way I was able to pass as a parameter the selected ids. If your grid hasn't many records, a simpler solution would be, I think, to simply reload the results, simulating a collection – Lou Nik Mar 26 at 14:48
1

You were so close! On Magento 2 grids

Mass Action Can Work Two Ways.

For smaller collections, I find this works find

protected function massAction(AbstractCollection $collection) {

$invoiceIds = $this->getRequest()->getParam('selected');

For larger collections, it fires the Execute function. This example is from the invoice grid

public function execute()
    {

        $collection = $this->filter->getCollection($this->invoicecollectionFactory->create());
1
  • hello @elfling, what is the solution for this issue, I am also facing the same problem – jafar pinjar Mar 25 at 11:15
0

Update your listing file

    <massaction name="listing_massaction" component="Magento_Ui/js/grid/tree-massactions">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="selectProvider" xsi:type="string">your_custom_listing.your_custom_listing.my_provider_columns.ids</item>
                <item name="component" xsi:type="string">Magento_Ui/js/grid/tree-massactions</item>
                <item name="indexField" xsi:type="string">id</item>
            </item>
        </argument>
        <action name="is_delete">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="type" xsi:type="string">delete</item>
                    <item name="label" xsi:type="string" translate="true">Delete</item>
                    <item name="url" xsi:type="url" path="your_admin_route_name/your_admin_contoller_name/massDelete">
                    </item>
                    <item name="confirm" xsi:type="array">
                        <item name="title" xsi:type="string" translate="true">Delete items</item>
                        <item name="message" xsi:type="string" translate="true">Are you sure you wan't to delete selected items?</item>
                    </item>
                </item>
            </argument>
        </action>
    </massaction>

And your mass delete file is here

<?php

namespace VendoreName\ModuleName\Controller\Adminhtml\YourContollerName;

use VendoreName\ModuleName\Model\ResourceModel\YourModelName\CollectionFactory;
use VendoreName\ModuleName\Model\YourModelNameFactory;
use Magento\Backend\App\Action\Context;
use Magento\Framework\Controller\ResultFactory;
use Magento\Ui\Component\MassAction\Filter;

class MassDelete extends \Magento\Backend\App\Action
{
    protected $filter;
    protected $collectionFactory;
    protected $CustomeModel;

    public function __construct(
        Context $context,
        Filter $filter,
        CollectionFactory $collectionFactory,
        YourModelNameFactory $CustomeModel
    ) {
        $this->filter = $filter;
        $this->collectionFactory = $collectionFactory;
        $this->CustomeModel = $CustomeModel;
        parent::__construct($context);
    }

    public function execute()
    {
        $CustomData = $this->collectionFactory->create();
        foreach ($CustomData as $value) {
            $templateId[] = $value['id'];
        }
        $parameterData = $this->getRequest()->getParams('id');
        $selectedAppsid = $this->getRequest()->getParams('id');
        if (array_key_exists("selected", $parameterData)) {
            $selectedAppsid = $parameterData['selected'];
        }
        if (array_key_exists("excluded", $parameterData)) {
            if ($parameterData['excluded'] == 'false') {
                $selectedAppsid = $templateId;
            } else {
                $selectedAppsid = array_diff($templateId, $parameterData['excluded']);
            }
        }
        $collection = $this->collectionFactory->create();
        $collection->addFieldToFilter('id', ['in' => $selectedAppsid]);
        $delete = 0;
        $model = [];
        foreach ($collection as $item) {
            $this->deleteById($item->getId());
            $delete++;
        }
        $this->messageManager->addSuccess(__('A total of %1 Records have been deleted.', $delete));
        $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
        return $resultRedirect->setPath('*/*/');
    }

    public function deleteById($id)
    {
        $item = $this->CustomeModel->load($id);
        $item->delete();
    }
}

I Hope This Helps You.

0

Use a custom JS AMD module that extends from Magento_Ui/js/grid/tree-massactions.

You will configure the mass listing to use this module on this node here <massaction name="listing_massaction" component="Vendor_Module/path/to/js/module">

In the custom JS override the following method from the parent

defaultCallback: function (action, data) {

Change

var itemsType = data.excludeMode ? 'excluded' : 'selected',

With

var itemsType = 'selected',

Keep everything else from the parent method.

Clean cache. Redeploy static-content if needed.

There is a drawback though, I'm almost sure this will send you only the ids from the current page, I say this for obvious reasons the markup for the other pages is not yet loaded so the checkboxes can not be checked. I suspect that is the point of the 'excluded' feature as well.

If you do not know how to extend Magento_Ui/js/grid/tree-massactions take a look here Use custom JS official docs

1
  • Yea, you are right, it's only send the ids from the current page, which is not the correct answer we're looking for. – fudu 9 hours ago
0

Can you refer code used in following blog..See approved solution.

Admin Grid "Select All" for mass action only sends the visible IDs

In above link there is code for select All for mass action.

1
  • Maybe you are misunderstanding the request, he say no "selected" parameter is passed. Instead, there is a parameter "excluded" false and no ids are passed to my controller. But your provided link is about "selected" parameter is only from the current page. – fudu 10 hours ago

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.