1

How to add a custom grid in a new tab in product edit page using UI_Component method?

This custom grid fetches collection from a custom table.

4

1 Answer 1

3

You can add it using modifier and UI component. Let's say my module name is Codextblog/Customtab.

Add Modifier app/code/Codextblog/Customtab/etc/adminhtml/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<virtualType name="Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Pool">
    <arguments>
        <argument name="modifiers" xsi:type="array">
            <item name="custom-tab-with-content" xsi:type="array">
                <item name="class" xsi:type="string">Codextblog\Customtab\Ui\DataProvider\Product\Form\Modifier\CustomTab</item>
                <item name="sortOrder" xsi:type="number">10</item>
            </item>
        </argument>
    </arguments>
</virtualType>
</config>

Add custom tab

<?php
namespace Codextblog\Customtab\Ui\DataProvider\Product\Form\Modifier;

use Magento\Catalog\Model\Locator\LocatorInterface;
use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier;
use Magento\Framework\Stdlib\ArrayManager;
use Magento\Framework\UrlInterface;
use Magento\Ui\Component\Container;
use Magento\Ui\Component\Form\Fieldset;


class CustomTab extends AbstractModifier
{

const SAMPLE_FIELDSET_NAME = 'custom_fieldset';
const SAMPLE_FIELD_NAME = 'is_custom';


protected $_backendUrl;
protected $_productloader;
protected $_modelCustomtabFactory;

/**
 * @var \Magento\Catalog\Model\Locator\LocatorInterface
 */
protected $locator;

/**
 * @var ArrayManager
 */
protected $arrayManager;

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

/**
 * @var array
 */
protected $meta = [];

/**
 * @param LocatorInterface $locator
 * @param ArrayManager $arrayManager
 * @param UrlInterface $urlBuilder
 */
public function __construct(
    LocatorInterface $locator,
    ArrayManager $arrayManager,
    UrlInterface $urlBuilder,
    \Magento\Catalog\Model\ProductFactory $_productloader,
    \Magento\Backend\Model\UrlInterface $backendUrl
) {
    $this->locator = $locator;
    $this->arrayManager = $arrayManager;
    $this->urlBuilder = $urlBuilder;
    $this->_productloader = $_productloader;
    $this->_backendUrl = $backendUrl;
}

public function modifyData(array $data)
{
    return $data;
}

public function modifyMeta(array $meta)
{
    $this->meta = $meta;
    $this->addCustomTab();

    return $this->meta;
}

protected function addCustomTab()
{
    $this->meta = array_merge_recursive(
        $this->meta,
        [
            static::SAMPLE_FIELDSET_NAME => $this->getTabConfig(),
        ]
    );
}

protected function getTabConfig()
{
    return [
        'arguments' => [
            'data' => [
                'config' => [
                    'label' => __('Custom Tab'),
                    'componentType' => Fieldset::NAME,
                    'dataScope' => '',
                    'provider' => static::FORM_NAME . '.product_form_data_source',
                    'ns' => static::FORM_NAME,
                    'collapsible' => true,
                ],
            ],
        ],
        'children' => [
            static::SAMPLE_FIELD_NAME => [
                'arguments' => [
                    'data' => [
                        'config' => [
                            'autoRender' => true,
                            'componentType' => 'insertListing',
                            'dataScope' => 'custom_listing',
                            'externalProvider' => 'custom_listing.custom_listing_data_source',
                            'selectionsProvider' => 'custom_listing.custom_listing.product_columns.ids',
                            'ns' => 'custom_listing',
                            'render_url' => $this->urlBuilder->getUrl('mui/index/render'),
                            'realTimeLink' => false,
                            'behaviourType' => 'simple',
                            'externalFilterMode' => true,
                            'imports' => [
                                'productId' => '${ $.provider }:data.product.current_product_id'
                            ],
                            'exports' => [
                                'productId' => '${ $.externalProvider }:params.current_product_id'
                            ],

                        ],
                    ],
                ],
                'children' => [],
            ],
        ],
    ];
}

}

Add dataprovider file app/code/Codextblog/Customtab/Ui/Dataprovider/Product/CustomDataProvider.php

<?php

namespace Codextblog\Customtab\Ui\DataProvider\Product;

use Magento\Framework\App\RequestInterface;
use Magento\Ui\DataProvider\AbstractDataProvider;
use Codextblog\Custom\Model\ResourceModel\Custom\CollectionFactory;
use Codextblog\Custom\Model\ResourceModel\Custom\Collection;
use Codextblog\Custom\Model\Custom;


class CustomDataProvider extends AbstractDataProvider
{
/**
 * @var CollectionFactory
 */
protected $collectionFactory;

/**
 * @var RequestInterface
 */
protected $request;

/**
 * @param string $name
 * @param string $primaryFieldName
 * @param string $requestFieldName
 * @param CollectionFactory $collectionFactory
 * @param RequestInterface $request
 * @param array $meta
 * @param array $data
 */
public function __construct(
    $name,
    $primaryFieldName,
    $requestFieldName,
    CollectionFactory $collectionFactory,
    RequestInterface $request,
    array $meta = [],
    array $data = []
) {
    parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data);
    $this->collectionFactory = $collectionFactory;
    $this->collection = $this->collectionFactory->create();
    $this->request = $request;
}

/**
 * {@inheritdoc}
 */
public function getData()
{
    $this->getCollection();

    $arrItems = [
        'totalRecords' => $this->getCollection()->getSize(),
        'items' => [],
    ];

    foreach ($this->getCollection() as $item) {
        $arrItems['items'][] = $item->toArray([]);
    }

    return $arrItems;
}

/**
 * {@inheritdoc}
 */
public function addFilter(\Magento\Framework\Api\Filter $filter)
{
    $field = $filter->getField();



    if (in_array($field, ['title', 'nickname', 'detail'])) {
        $filter->setField($field);
    }

    parent::addFilter($filter);
}
}

Here Codextblog\Custom\Model\ResourceModel\Custom\CollectionFactory is the collection of a module which grid will be display in a custom tab.

Create ui component app/code/Codextblog/Customtab/view/adminhtml/ui_component/custom_listing.xml

<?xml version="1.0" encoding="UTF-8"?>

<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<argument name="data" xsi:type="array">
    <item name="js_config" xsi:type="array">
        <item name="provider" xsi:type="string">custom_listing.custom_listing_data_source</item>
        <item name="deps" xsi:type="string">custom_listing.custom_listing_data_source</item>
    </item>
    <item name="spinner" xsi:type="string">custom_columns</item>
</argument>
<dataSource name="custom_listing_data_source">
    <argument name="dataProvider" xsi:type="configurableObject">
        <argument name="class" xsi:type="string">Codextblog\Customtab\Ui\DataProvider\Product\CustomDataProvider</argument>
        <argument name="name" xsi:type="string">custom_listing_data_source</argument>
        <argument name="primaryFieldName" xsi:type="string">id</argument>
        <argument name="requestFieldName" xsi:type="string">id</argument>
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="component" xsi:type="string">Magento_Ui/js/grid/provider</item>
                <item name="update_url" xsi:type="url" path="mui/index/render"/>
                <item name="storageConfig" xsi:type="array">
                    <item name="cacheRequests" xsi:type="boolean">false</item>
                </item>
            </item>
        </argument>
    </argument>
</dataSource>
<listingToolbar name="listing_top">
    <filters name="listing_filters">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="statefull" xsi:type="array">
                    <item name="applied" xsi:type="boolean">false</item>
                </item>
                <item name="params" xsi:type="array">
                    <item name="filters_modifier" xsi:type="array"/>
                </item>
            </item>
        </argument>
    </filters>
    <paging name="listing_paging"/>
</listingToolbar>
<columns name="custom_columns" class="Magento\Ui\Component\Listing\Columns">
    <argument name="data" xsi:type="array">
        <item name="config" xsi:type="array">
            <item name="childDefaults" xsi:type="array">
                <item name="fieldAction" xsi:type="array">
                    <item name="provider" xsi:type="string">customGrid</item>
                    <item name="target" xsi:type="string">selectReview</item>
                    <item name="params" xsi:type="array">
                        <item name="0" xsi:type="string">${ $.$data.rowIndex }</item>
                    </item>
                </item>
            </item>
        </item>
    </argument>
    <column name="id">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="filter" xsi:type="string">textRange</item>
                <item name="sorting" xsi:type="string">asc</item>
                <item name="label" xsi:type="string" translate="true">ID</item>
                <item name="sortOrder" xsi:type="number">0</item>
            </item>
        </argument>
    </column>
    <column name="name">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="filter" xsi:type="string">text</item>
                <item name="label" xsi:type="string" translate="true">Name</item>
                <item name="sortOrder" xsi:type="number">30</item>
                <item name="truncate" xsi:type="number">50</item>
                <item name="nl2br" xsi:type="boolean">true</item>
                <item name="escape" xsi:type="boolean">true</item>
            </item>
        </argument>
    </column>
</columns>
</listing>
6
  • I need the the custom table collection based on the product_id, in that collection how can i add current product id for the collection filter(CustomDataProvider.php)
    – senthil
    Apr 8, 2019 at 14:03
  • @senthil Did you try this $this->getRequest()->getParam('id'); Apr 9, 2019 at 4:46
  • Yes, but i am getting the following error. Fatal error: Method Magento\Ui\TemplateEngine\Xhtml\Result::__toString() must not throw an exception, caught Error: Call to undefined method Learn\ProductQA\Ui\DataProvider\Product\QuestionAnswerDataProvider::getRequest() in D:\workspace\Magento\m226\vendor\magento\module-ui\Controller\Adminhtml\Index\Render.php on line 0 So, instead of that i used the $this->_request->getParams(), but in this i don't see any product_id, because the grid load by ajax
    – senthil
    Apr 9, 2019 at 5:19
  • @mariun , how can i get the current product id in the product edit page custom tab collection grid, i tried $_REQUEST , it returning Array ( [namespace] => questionanswer_grid_listing [isAjax] => true )
    – senthil
    Apr 26, 2019 at 6:41
  • In the function getData() in CustomDataProvider.php is called by Magento 2 times. The first call is made by GET to {{domain_admin}}/mui/index/render/?namespace= custom_listing&isAjax=true, in which only $this->request->getParams() the namespace variable and isAjax appear. And in the second call is made by POST and receives more parameters. Among them, the current_product_id
    – raumatbel
    Mar 23, 2021 at 13:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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