How to use Magento 2 UI component

UI Components are an ambitious new approach to building user interface elements in Magento 2, and much of the new admin console is built on this functionality. The main purpose is to combine HTML and JavaScript content, allowing the creation of new components with any form and function possible. In the following article, we will learn how Magento 2 use UI component to create simple grid.

Assume that you have read through and practiced the articles create Magento 2 extension and Magento 2 create model collection or are knowledgeable about it.

Now, we will use UI Components to create a grid for managing messages on the admin backend.

1. Create admin route

Create file app\code\Magerubik\Simple\etc\adminhtml\routes.xml with below content.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
    <router id="admin">
        <route id="simple" frontName="simple">
			<module name="Magerubik_Simple" before="Magento_Backend" />
        </route>
    </router>
</config>

2. Create admin controller

Create file app\code\Magerubik\Simple\Controller\Adminhtml\Message\Index.php with below content.

<?php
namespace Magerubik\Simple\Controller\Adminhtml\Message;
class Index extends \Magento\Backend\App\Action
{
    protected $resultPageFactory;
    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory
    ) {
        parent::__construct($context);
        $this->resultPageFactory = $resultPageFactory;
    }
    public function execute()
    {
        return $this->resultPageFactory->create();
    }
}

3. Create Layout

Create file app\code\Magerubik\Simple\view\adminhtml\layout\simple_message_index.xml with below content.

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
		<referenceBlock name="page.title">
			<action method="setPageTitle">
				<argument translate="true" name="title" xsi:type="string">Manage Message</argument>
			</action>
		</referenceBlock>
		<referenceContainer name="content">
            <uiComponent name="message_listing" />
        </referenceContainer>
    </body>
</page>

4. Create Data Provider

Create file app\code\Magerubik\Simple\etc\di.xml with below content.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
        <arguments>
            <argument name="collections" xsi:type="array">
                <item name="message_listing_data_source" xsi:type="string">message_collection</item>
            </argument>
        </arguments>
    </type>
    <virtualType name="message_collection" type="Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult">
        <arguments>
            <argument name="mainTable" xsi:type="string">vendor_message</argument>
            <argument name="resourceModel" xsi:type="string">Magerubik\Simple\Model\ResourceModel\Message</argument>
        </arguments>
    </virtualType>
</config>

5. Use Magento 2 UI component create simple grid

Create file app\code\Magerubik\Simple\view\adminhtml\ui_component\message_listing.xml with below content.

<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">message_listing.message_listing_data_source</item>
        </item>
    </argument>
    <settings>
        <spinner>message_columns</spinner>
        <deps>
            <dep>message_listing.message_listing_data_source</dep>
        </deps>
        <buttons>
            <button name="new">
                <url path="*/*/new"/>
                <class>primary</class>
                <label translate="true">Add new</label>
            </button>
        </buttons>
    </settings>
    <listingToolbar name="listing_top">
        <settings>
            <sticky>true</sticky>
        </settings>
        <bookmark name="bookmarks"/>
        <exportButton name="export_button"/>
        <columnsControls name="columns_controls"/>
        <filters name="listing_filters" />
        <paging name="listing_paging"/>
        <massaction name="listing_massaction">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/tree-massactions</item>
                </item>
            </argument>
            <action name="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="*/*/delete"/>
                        <item name="confirm" xsi:type="array">
                            <item name="title" xsi:type="string" translate="true">Delete Row</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>
    </listingToolbar>
    <dataSource name="message_listing_data_source" component="Magento_Ui/js/grid/provider">
        <settings>
            <updateUrl path="mui/index/render"/>
            <storageConfig>
                <param name="indexField" xsi:type="string">messages_id</param>
            </storageConfig>
        </settings>
        <aclResource>Magerubik_Simple::listing</aclResource>
        <dataProvider class="Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider" name="message_listing_data_source">
            <settings>
                <requestFieldName>id</requestFieldName>
                <primaryFieldName>messages_id</primaryFieldName>
            </settings>
        </dataProvider>
    </dataSource>
    <!-- columns -->
    <columns name="message_columns">
        <selectionsColumn name="ids">
            <settings>
                <indexField>messages_id</indexField>
            </settings>
        </selectionsColumn>
        <column name="messages_id" sortOrder="2">
            <settings>
                <filter>text</filter>
                <label translate="true">ID</label>
            </settings>
        </column>
		<column name="user_id" class="Magerubik\Simple\Ui\Component\Listing\Columns\Customerlink">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="filter" xsi:type="string">text</item>
                    <item name="sorting" xsi:type="string">asc</item>
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/actions</item>
					<item name="bodyTmpl" xsi:type="string">ui/grid/cells/html</item>
					<item name="resizeEnabled" xsi:type="boolean">false</item>
                    <item name="resizeDefaultWidth" xsi:type="string">200</item>
                    <item name="indexField" xsi:type="string">messages_id</item>
                    <item name="label" xsi:type="string" translate="true">User Name</item>
                    <item name="sortOrder" xsi:type="number">3</item>
                </item>
            </argument>
        </column>
        <column name="title" sortOrder="4">
            <settings>
                <filter>text</filter>
                <label translate="true">Title</label>
            </settings>
        </column>
		<column name="description" sortOrder="5">
            <settings>
                <filter>text</filter>
                <label translate="true">Description</label>
            </settings>
        </column>
		<column name="status" sortOrder="6">
            <settings>
                <filter>text</filter>
                <label translate="true">Status</label>
            </settings>
        </column>
		<column name="created_at" class="Magento\Ui\Component\Listing\Columns\Date">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="filter" xsi:type="string">dateRange</item>
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/date</item>
                    <item name="dataType" xsi:type="string">date</item>
                    <item name="label" xsi:type="string" translate="true">Date</item>
                    <item name="sortOrder" xsi:type="number">7</item>
                </item>
            </argument>
        </column>
    </columns>
</listing>

Then create file app\code\Magerubik\Simple\Ui\Component\Listing\Columns\Customerlink.php with below content to make customer link col.

<?php
namespace Magerubik\Simple\Ui\Component\Listing\Columns;
use Magento\Framework\UrlInterface;
use Magento\Framework\View\Element\UiComponent\ContextInterface;
use Magento\Framework\View\Element\UiComponentFactory;
use Magento\Ui\Component\Listing\Columns\Column;
class Customerlink extends Column
{
    protected $urlBuilder;
    public function __construct(
        ContextInterface $context,
        UiComponentFactory $uiComponentFactory,
        UrlInterface $urlBuilder,
        array $components = [],
        array $data = []
    ) {
        $this->urlBuilder = $urlBuilder;
        parent::__construct($context, $uiComponentFactory, $components, $data);
    }
    public function prepareDataSource(array $dataSource)
    {
        if (isset($dataSource['data']['items'])) {
            $fieldName = $this->getData('name');
            foreach ($dataSource['data']['items'] as &$item) {
				$customerId = $item['user_id'];
				$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
				$customerData = $objectManager->create('Magento\Customer\Model\Customer')->load($customerId);
				$userName = $customerData->getFirstname() . ' ' . $customerData->getLastname();
				$item[$fieldName] = "<a href='" . $this->urlBuilder->getUrl('customer/index/edit', ['id' => $item['user_id']]) . "' target='blank' title='".__('View Customer')."'>" . $userName . "</a>";
            }
        }

        return $dataSource;
    }
}

6. Create admin menu

Create file app\code\Magerubik\Simple\etc\adminhtml\menu.xml with below content:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Backend:etc/menu.xsd">
    <menu>
        <add id="Magerubik_Simple::menu" title="Magerubik" module="Magerubik_Simple" translate="title" sortOrder="68" resource="Magerubik_Simple::menu"/>
        <add id="Magerubik_Simple::manager" title="Manager Message" module="Magerubik_Simple" translate="title" sortOrder="1068" parent="Magerubik_Simple::menu" resource="Magerubik_Simple::manager" action="simple/message"/>
    </menu>
</config>

7. Go to backend check it working

If you can see the below screenshot everything is ok.

Magento 2 admin menu
Magento UI Component

Now you know how to use Magento 2 UI component create simple grid. In the next posts, we will learn how to use it to create form import data. Also, you can read more about the Magento default component here. Contact us if you face any problems during the installation process.

You can download the demo code for this entire series from GitHub