Magento – How to show a custom grid in a custom tab in product edit page admin Magento-2

adminhtmlcatalogmagento2.2productproduct-grid

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.

Best Answer

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>
Related Topic