Magento UI Components – Custom Products Grid, pt. 1: Preparation

A quick intro on UI Components

In this article, I will take you through a step-by-step process of creating a Custom Products Grid in the Magento 2 environment. The upgraded platform comes with a set of UI Components as a standard module. You can use a UI Component for defining a whole page as a composition of fragments such as buttons and tables.

With UI Components, we get quick features like:

  • pagination,
  • filtering by values,
  • UI bookmarks,
  • selectable columns which should be hidden or displayed,
  • data export to external files,
  • mass actions on selected rows,
  • inline edit row.

If you already work with Magento 2, I assume that you know how to create a new module with a data model structure and a simple controller that overrides the execute method. Let’s go.

UI Component - the Custom Products Grid: Preparations

Imagine that you need to present some kind of a data collection in the administrator panel (Magento backend). In order to do this, the good practice is to create a new view by using a UI Component listing.

We’ll discuss it in a series of 3 articles and today we’ll talk about preparation for creating the views.

1. New module

For starters, I created a new module in Magento 2 with a data model structure. The vendor name in the module will be called “Magently” and the module name: “MyUiComponent”.

2. Data structure

First of all, we have to figure out what data we want to present. For the purpose of this article I prepared the following structure with different types of data:

The name of the table will be “my_products”. Of course, for this data structure, we have to create a new table in the database (using the Setup/UpgradeSchema script), create a model, a resource model class and the collection class with their corresponding interfaces. I will not describe how to do this as this is not the main topic of this article.

3. Controller and layout for the UI Component

Now, we have to create a controller. I assume that you already know how to create a simple controller that extends from the \Magento\Backend\App\Action class and overrides the execute method. In our example, this controller will be located in the Controller/Adminhtml/Index/Index.php file.

Next, add your own routes.xml in the etc/adminhtml location if you haven’t already.

html
1 2 3 4 5 6 7 8 9 10 11 // file: Magently/MyUiComponent/etc/adminhtml/routes.xml <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd"> <router id="admin"> <route id="my_products" frontName="my_products"> <module name="Magently_MyUiComponent"/> </route> </router> </config>

So now we have to create a layout in an XML file in view/adminhtml/layout location. The name of the file will be _.xml. In our example this will be: my_products_index_index.xml

html
1 2 3 4 5 6 7 8 9 10 11 12 // file: Magently/MyUiCOmponent/view/adminhtml/layout/my_products_index_index.xml <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <update handle="styles"/> <body> <referenceContainer name="content"> <uiComponent name="myproducts_listing"/> </referenceContainer> </body> </page>

In the layout, we need to add a named “myproducts_listing”, which is very important. Please note that we don’t have to implement a block class with a template. The UI Component is all we need.

4. Prepare filters and data provider virtual type

Now, we have to prepare some references to filters and the data provider which will be used by the UI Component. The easiest way to do this is by creating some virtual types in the etc/di.xml file.

Adding regular and full-text filters

First, we will change the dependency injection for the data provider collection:

html
1 2 3 4 5 6 7 8 9 10 11 // file: Magently/MyUiComponent/etc/di.xml <type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory"> <arguments> <argument name="collections" xsi:type="array"> <item name="myproducts_listing_data_source" xsi:type="string"> Magently\MyUiComponent\Model\ResourceModel\MyProducts\Grid\Collection </item> </argument> </arguments> </type>

What happened here? In we added a class for which we want to assign new values for the arguments. In our case it is the Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory class.

You can check that this class has an array called “collections” in its own constructor. Therefore we have to refer to this parameter and set a new array as a means of collecting our data from the database. I named the key of array  myproducts_listing_data_source. We will be using this name later in the UI Component XML file.

The value of the array indicates a virtual type of collection called: Magently\MyUiComponent\Model\ResourceModel\MyProducts\Grid\Collection. This class doesn’t exist yet and we will create it now, by adding the next part of the code in the etc/di.xml file:

html
1 2 3 4 5 6 7 8 9 10 11 12 // file: Magently/MyUiComponent/etc/di.xml <virtualType name="Magently\MyUiComponent\Model\ResourceModel\MyProducts\Grid\Collection" type="Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult"> <arguments> <argument name="mainTable" xsi:type="string">my_products</argument> <argument name="resourceModel" xsi:type="string"> Magently\MyUiComponent\Model\ResourceModel\MyProducts </argument> </arguments> </virtualType>

In the part above, we simulate the virtual type class as a collection of data from our database.

Please note that this virtual type class is being represented by SearchResult. For this class, we set two arguments: mainTable (containing table name) and resourceModel (containing the path to the resource model of our table).

Now we can create another virtual type as a filter pool:

html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // file: Magently/MyUiComponent/etc/di.xml <virtualType name="MyProductsGridFilterPool" type="Magento\Framework\View\Element\UiComponent\DataProvider\FilterPool"> <arguments> <argument name="appliers" xsi:type="array"> <item name="regular" xsi:type="object"> Magento\Framework\View\Element\UiComponent\DataProvider\RegularFilter </item> <item name="fulltext" xsi:type="object"> Magento\Framework\View\Element\UiComponent\DataProvider\FulltextFilter </item> </argument> </arguments> </virtualType>

I named it MyProductsGridFilterPool and we will refer to this name later. The class Magento\Framework\View\Element\UiComponent\DataProvider\FilterPool has one argument in its own constructor. It’s an array called “appliers”. We refer to this argument in order to insert two items into it: a regular filter and a full-text one.

Adding a data provider class

Finally, we will add our data provider class. We can do it by creating another virtual type in etc/di.xml:

html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 // file: Magently/MyUiComponent/etc/di.xml <virtualType name="MyProductsGridDataProvider" type="Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider"> <arguments> <argument name="collection" xsi:type="object" shared="false"> Magently\MyUiComponent\Model\ResourceModel\MyProducts\Collection </argument> <argument name="filterPool" xsi:type="object" shared="false"> MyProductsGridFilterPool </argument> </arguments> </virtualType>

The name of our data provider, called MyProductsGridDataProvider, will be used later in the UI Component XML file. Inside we set the values for collection and filter pool. For collection, we set a path to our data collection class. For filter pool, we use the previously defined MyProductsGridFilterPool.

Custom Products Grid - The summary

That’s all in this part. In this article:

  • we made preparations for creating a view based on a UI Component,
  • created data which will be presented in the grid,
  • learned how to prepare filters and the data provider.

I will explore the topic further in the second part of this article, where we will go through creating an XML file with our UI Component.