Menu Close
    Convert your store into Magento 2 Multi Vendor Marketplace

    Magento 2 Development 14: More about Admin Grid

    In the previous blog we created a very basic admin grid. Here we will modify it little bit.

    Class of a Column

    In the previous grid we have not shown the content of the blog. That it is because the blog content will be large and it will not be practical to show the whole content. But we can show 20 characters just like we did on front-end.

    Let’s see how we can do that. We are adding a new column in the grid, so we need to change the content of ui component file view/adminhtml/ui_component/blogmanager_blog_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">blogmanager_blog_listing.blogmanager_blog_listing_data_source</item>
                <item name="deps" xsi:type="string">blogmanager_blog_listing.blogmanager_blog_listing_data_source</item>
            </item>
            <item name="spinner" xsi:type="string">blogmanager_blog_columns</item>
        </argument>
        <dataSource name="blogmanager_blog_listing_data_source">
            <argument name="dataProvider" xsi:type="configurableObject">
                <argument name="class" xsi:type="string">Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider</argument>
                <argument name="name" xsi:type="string">blogmanager_blog_listing_data_source</argument>
                <argument name="primaryFieldName" xsi:type="string">entity_id</argument>
                <argument name="requestFieldName" xsi:type="string">entity_id</argument>
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                    <item name="update_url" xsi:type="url" path="mui/index/render"/>
                    <item name="storageConfig" xsi:type="array">
                        <item name="indexField" xsi:type="string">entity_id</item>
                    </item>
                    </item>
                </argument>
            </argument>
            <argument name="data" xsi:type="array">
                <item name="js_config" xsi:type="array">
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/provider</item>
                </item>
            </argument>
        </dataSource>
        <listingToolbar name="listing_top">
            <bookmark name="bookmarks"/>
            <columnsControls name="columns_controls"/>
            <filters name="listing_filters">
                    <argument name="data" xsi:type="array">
                        <item name="config" xsi:type="array">
                            <item name="templates" xsi:type="array">
                                <item name="filters" xsi:type="array">
                                    <item name="select" xsi:type="array">
                                        <item name="component" xsi:type="string">Magento_Ui/js/form/element/ui-select</item>
                                        <item name="template" xsi:type="string">ui/grid/filters/elements/ui-select</item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </argument>
            </filters>
            <paging name="listing_paging"/>
        </listingToolbar>
        <columns name="blogmanager_blog_columns">
            <column name="entity_id">
                <settings>
                    <filter>textRange</filter>
                    <label translate="true">ID</label>
                    <resizeDefaultWidth>25</resizeDefaultWidth>
                </settings>
            </column>
            <column name="user_id">
                <settings>
                    <filter>text</filter>
                    <label translate="true">User</label>
                </settings>
            </column>
            <column name="title">
                <settings>
                    <filter>text</filter>
                    <label translate="true">Title</label>
                </settings>
            </column>
            <column name="content" class="Webkul\BlogManager\Ui\Component\Listing\Columns\Content">
                <settings>
                    <filter>false</filter>
                    <sortable>false</sortable>
                    <label translate="true">Content</label>
                </settings>
            </column>
            <column name="status">
                <settings>
                    <filter>text</filter>
                    <sortable>false</sortable>
                    <label translate="true">Status</label>
                </settings>
            </column>
            <column name="updated_at" component="Magento_Ui/js/grid/columns/date">
                <settings>
                    <filter>dateRange</filter>
                    <dataType>date</dataType>
                    <label translate="true">Updated</label>
                </settings>
            </column>
            <column name="created_at" component="Magento_Ui/js/grid/columns/date">
                <settings>
                    <filter>dateRange</filter>
                    <dataType>date</dataType>
                    <label translate="true">Created</label>
                </settings>
            </column>
        </columns>
    </listing>

    Please use online diff checker to easily see what’s different from last version of this file. The only thing different here is that we have added a new column tag for content. In that tag we have used class=”Webkul\BlogManager\Ui\Component\Listing\Columns\Content”. By adding the class we are telling magento that we will provide the data for this column with this class. All the ui component related php files are created under Ui/Component folder.

    Now let’s create the Content class as Ui/Component/Listing/Columns/Content.php

    <?php
    namespace Webkul\BlogManager\Ui\Component\Listing\Columns;
    
    class Content extends \Magento\Ui\Component\Listing\Columns\Column
    {
        public function prepareDataSource(array $dataSource)
        {
            if (isset($dataSource['data']['items'])) {
                $fieldName = 'content';
                foreach ($dataSource['data']['items'] as &$item) {
                    $item[$fieldName] = substr($item[$fieldName], 0, 20).'...';
                }
            }
            return $dataSource;
        }
    }

    So what we are doing here is that we are looping through all the rows and updating the content column to show only 20 characters. For updating the data, we are using prepareDataSource method.

    We use this technique when we need perform some operations before showing the data or when the data is not coming from our table.

    Now if you browse, you will see the content column,

    2021-03-05_11-03


    Select Option type Column

    We will be implementing a feature in next few blogs with which admin will be able to manage the status of the blog. That’s why we have added the status column, which will be 0 or 1. In the status column we are showing 0 or 1 instead it will be better if we show text labels such as Disabled or Enabled.

    So for that as you may have guessed we need to make changes in view/adminhtml/ui_component/blogmanager_blog_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">blogmanager_blog_listing.blogmanager_blog_listing_data_source</item>
                <item name="deps" xsi:type="string">blogmanager_blog_listing.blogmanager_blog_listing_data_source</item>
            </item>
            <item name="spinner" xsi:type="string">blogmanager_blog_columns</item>
        </argument>
        <dataSource name="blogmanager_blog_listing_data_source">
            <argument name="dataProvider" xsi:type="configurableObject">
                <argument name="class" xsi:type="string">Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider</argument>
                <argument name="name" xsi:type="string">blogmanager_blog_listing_data_source</argument>
                <argument name="primaryFieldName" xsi:type="string">entity_id</argument>
                <argument name="requestFieldName" xsi:type="string">entity_id</argument>
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                    <item name="update_url" xsi:type="url" path="mui/index/render"/>
                    <item name="storageConfig" xsi:type="array">
                        <item name="indexField" xsi:type="string">entity_id</item>
                    </item>
                    </item>
                </argument>
            </argument>
            <argument name="data" xsi:type="array">
                <item name="js_config" xsi:type="array">
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/provider</item>
                </item>
            </argument>
        </dataSource>
        <listingToolbar name="listing_top">
            <bookmark name="bookmarks"/>
            <columnsControls name="columns_controls"/>
            <filters name="listing_filters">
                    <argument name="data" xsi:type="array">
                        <item name="config" xsi:type="array">
                            <item name="templates" xsi:type="array">
                                <item name="filters" xsi:type="array">
                                    <item name="select" xsi:type="array">
                                        <item name="component" xsi:type="string">Magento_Ui/js/form/element/ui-select</item>
                                        <item name="template" xsi:type="string">ui/grid/filters/elements/ui-select</item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </argument>
            </filters>
            <paging name="listing_paging"/>
        </listingToolbar>
        <columns name="blogmanager_blog_columns">
            <column name="entity_id">
                <settings>
                    <filter>textRange</filter>
                    <label translate="true">ID</label>
                    <resizeDefaultWidth>25</resizeDefaultWidth>
                </settings>
            </column>
            <column name="user_id">
                <settings>
                    <filter>text</filter>
                    <label translate="true">User</label>
                </settings>
            </column>
            <column name="title">
                <settings>
                    <filter>text</filter>
                    <label translate="true">Title</label>
                </settings>
            </column>
            <column name="content" class="Webkul\BlogManager\Ui\Component\Listing\Columns\Content">
                <settings>
                    <filter>false</filter>
                    <sortable>false</sortable>
                    <label translate="true">Content</label>
                </settings>
            </column>
            <column name="status" component="Magento_Ui/js/grid/columns/select">
                <settings>
                    <options class="Webkul\BlogManager\Model\Blog\Status"/>
                    <dataType>select</dataType>
                    <filter>select</filter>
                    <sortable>false</sortable>
                    <label translate="true">Status</label>
                </settings>
            </column>
            <column name="updated_at" component="Magento_Ui/js/grid/columns/date">
                <settings>
                    <filter>dateRange</filter>
                    <dataType>date</dataType>
                    <label translate="true">Updated</label>
                </settings>
            </column>
            <column name="created_at" component="Magento_Ui/js/grid/columns/date">
                <settings>
                    <filter>dateRange</filter>
                    <dataType>date</dataType>
                    <label translate="true">Created</label>
                </settings>
            </column>
        </columns>
    </listing>

    Only changes you will find here are in the column tag. We are using select component which will replace the value with the label. We will provide key-value pair with the options class Webkul\BlogManager\Model\Blog\Status.

    In earlier section I mentioned that all the php files related to ui component should be in Ui/Component folder but this class is not limited to ui component, we can use it front-end too. So I will create it in model folder (it’s a general convention).

    In the filter tag we have mentioned that it is a select type so in filter section you will find multi-select dropdown for this column.

    Now let’s see the option class Model/Blog/Status.php

    <?php
    namespace Webkul\BlogManager\Model\Blog;
    
    use Magento\Framework\Data\OptionSourceInterface;
    
    class Status implements OptionSourceInterface
    {
        public function toOptionArray()
        {
            $options = [];
            $options[] = ['label' => 'Disabled', 'value' => 0];
            $options[] = ['label' => 'Enabled', 'value' => 1];
            return $options;
        }
    }

    Here we are creating an associative array and returning it in toOptionArray method.

    Whenever we have any such column which have options, like Yes/No or Bad/Neutral/Good, etc. we use this technique.

    Now if you check the Manage Blog page, you will see the changes,

    2021-03-05_12-16


    _renderFiltersBefore

    In the grid, we are showing the customer id in the User column which is not very helpful. Instead of the id we should show the customer name. We can do this by creating a class for the column but then we will not able to perform sorting and filtering on that column. This is because the column data get modified later. What I mean by this is that at first the original sql query get executed (in our virtual class) then we loop through the rows that we get as a result of the sql query.

    So if we want sorting and filtering to work we need modify the sql, for that we need to create the actual data provider class instead of using the virtual class.

    The customer data are stored in “customer_grid_flat” table. We can join our table with the customer table to get the name.

    Now let’s see this in code. First we will create the data provider class as Model/ResourceModel/Blog/Grid/Collection.php this is general convention to create the data provider or grid collection of a table alongside the collection class of that table.

    <?php
    namespace Webkul\BlogManager\Model\ResourceModel\Blog\Grid;
    
    use Magento\Framework\Api\Search\SearchResultInterface;
    use Magento\Framework\Search\AggregationInterface;
    use Webkul\BlogManager\Model\ResourceModel\Blog\Collection as BlogCollection;
    use Magento\Framework\Data\Collection\EntityFactoryInterface;
    use Psr\Log\LoggerInterface;
    use Magento\Framework\Data\Collection\Db\FetchStrategyInterface;
    use Magento\Framework\Event\ManagerInterface;
    use Magento\Framework\Model\ResourceModel\Db\AbstractDb;
    
    class Collection extends BlogCollection implements SearchResultInterface
    {
        public function __construct(
            EntityFactoryInterface $entityFactory,
            LoggerInterface $logger,
            FetchStrategyInterface $fetchStrategy,
            ManagerInterface $eventManager,
            $mainTable,
            $resourceModel,
            $model = \Magento\Framework\View\Element\UiComponent\DataProvider\Document::class,
            \Magento\Framework\DB\Adapter\AdapterInterface $connection = null,
            AbstractDb $resource = null
        ) {
            parent::__construct(
                $entityFactory,
                $logger,
                $fetchStrategy,
                $eventManager,
                $connection,
                $resource
            );
            $this->_init($model, $resourceModel);
            $this->setMainTable($mainTable);
        }
    
        public function getAggregations()
        {
            return $this->aggregations;
        }
    
        public function setAggregations($aggregations)
        {
            $this->aggregations = $aggregations;
        }
    
        public function getSearchCriteria()
        {
            return null;
        }
        
        public function setSearchCriteria(
            \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria = null
        ) {
            return $this;
        }
    
        public function getTotalCount()
        {
            return $this->getSize();
        }
    
        public function setTotalCount($totalCount)
        {
            return $this;
        }
    
        public function setItems(array $items = null)
        {
            return $this;
        }
    
        protected function _renderFiltersBefore()
        {
            $cgfTable = $this->getTable('customer_grid_flat');
            $this->getSelect()->joinLeft(
                $cgfTable.' as cgf',
                'main_table.user_id = cgf.entity_id',
                [
                    'user_name'=>'cgf.name'
                ]
            );
            parent::_renderFiltersBefore();
        }
        
        protected function _initSelect()
        {
            $this->addFilterToMap('user_name', 'cgf.name');
            parent::_initSelect();
        }
    }

    You don’t have to worry about all the methods. We have to understand only _renderFiltersBefore and _initSelect methods.

    $this->getTable(‘customer_grid_flat’) this will give the table name by adding the table prefix if any.

    We already know about the getSelect, $this->getSelect() will give access to the sql query of this class. We are performing left join with joinLeft method. Then we are joining customer_grid_flat table on ‘main_table.user_id = cgf.entity_id’, where cgf is alias for customer_grid_flat. And we are getting the customer name in user_name column.

    The actual sql query will look like,

    SELECT
       `main_table`.*,
       `cgf`.`name` AS `user_name` 
    FROM
       `blogmanager_blog` AS `main_table` 
       LEFT JOIN
          `customer_grid_flat` AS `cgf` 
          ON main_table.user_id = cgf.entity_id

    We also need to map this column alias in _initSelect method otherwise filter will not work.


    Now we need to modify the etc/di.xml because data provider is not a virtual class anymore,

    <?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="Webkul\BlogManager\Model\ResourceModel\Blog\Grid\Collection">
            <arguments>
                <argument name="mainTable" xsi:type="string">blogmanager_blog</argument>
                <argument name="resourceModel" xsi:type="string">Webkul\BlogManager\Model\ResourceModel\Blog</argument>
            </arguments>
        </type>
        <type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
            <arguments>
                <argument name="collections" xsi:type="array">
                    <item name="blogmanager_blog_listing_data_source" xsi:type="string">Webkul\BlogManager\Model\ResourceModel\Blog\Grid\Collection</item>
                </argument>
            </arguments>
        </type>
    </config>

    Here we have changed the tag virtualType to type. And we are providing the arguments as before. If you check the grid class you will find these arguments in the __construct method.


    We also need to change the ui component file view/adminhtml/ui_component/blogmanager_blog_listing.xml because the new column name is user_name

    <?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">blogmanager_blog_listing.blogmanager_blog_listing_data_source</item>
                <item name="deps" xsi:type="string">blogmanager_blog_listing.blogmanager_blog_listing_data_source</item>
            </item>
            <item name="spinner" xsi:type="string">blogmanager_blog_columns</item>
        </argument>
        <dataSource name="blogmanager_blog_listing_data_source">
            <argument name="dataProvider" xsi:type="configurableObject">
                <argument name="class" xsi:type="string">Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider</argument>
                <argument name="name" xsi:type="string">blogmanager_blog_listing_data_source</argument>
                <argument name="primaryFieldName" xsi:type="string">entity_id</argument>
                <argument name="requestFieldName" xsi:type="string">entity_id</argument>
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                    <item name="update_url" xsi:type="url" path="mui/index/render"/>
                    <item name="storageConfig" xsi:type="array">
                        <item name="indexField" xsi:type="string">entity_id</item>
                    </item>
                    </item>
                </argument>
            </argument>
            <argument name="data" xsi:type="array">
                <item name="js_config" xsi:type="array">
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/provider</item>
                </item>
            </argument>
        </dataSource>
        <listingToolbar name="listing_top">
            <bookmark name="bookmarks"/>
            <columnsControls name="columns_controls"/>
            <filters name="listing_filters">
                    <argument name="data" xsi:type="array">
                        <item name="config" xsi:type="array">
                            <item name="templates" xsi:type="array">
                                <item name="filters" xsi:type="array">
                                    <item name="select" xsi:type="array">
                                        <item name="component" xsi:type="string">Magento_Ui/js/form/element/ui-select</item>
                                        <item name="template" xsi:type="string">ui/grid/filters/elements/ui-select</item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </argument>
            </filters>
            <paging name="listing_paging"/>
        </listingToolbar>
        <columns name="blogmanager_blog_columns">
            <column name="entity_id">
                <settings>
                    <filter>textRange</filter>
                    <label translate="true">ID</label>
                    <resizeDefaultWidth>25</resizeDefaultWidth>
                </settings>
            </column>
            <column name="user_name">
                <settings>
                    <filter>text</filter>
                    <label translate="true">User</label>
                </settings>
            </column>
            <column name="title">
                <settings>
                    <filter>text</filter>
                    <label translate="true">Title</label>
                </settings>
            </column>
            <column name="content" class="Webkul\BlogManager\Ui\Component\Listing\Columns\Content">
                <settings>
                    <filter>false</filter>
                    <sortable>false</sortable>
                    <label translate="true">Content</label>
                </settings>
            </column>
            <column name="status" component="Magento_Ui/js/grid/columns/select">
                <settings>
                    <options class="Webkul\BlogManager\Model\Blog\Status"/>
                    <dataType>select</dataType>
                    <filter>select</filter>
                    <sortable>false</sortable>
                    <label translate="true">Status</label>
                </settings>
            </column>
            <column name="updated_at" component="Magento_Ui/js/grid/columns/date">
                <settings>
                    <filter>dateRange</filter>
                    <dataType>date</dataType>
                    <label translate="true">Updated</label>
                </settings>
            </column>
            <column name="created_at" component="Magento_Ui/js/grid/columns/date">
                <settings>
                    <filter>dateRange</filter>
                    <dataType>date</dataType>
                    <label translate="true">Created</label>
                </settings>
            </column>
        </columns>
    </listing>


    Now you should see something like,

    2021-03-05_13-47

    Please check out these blogs to learn more about join,

    Folder Structure,

    2021-03-05_14-22


    Next Blog -> Magento 2 Development 15: MassAction

    Previous Blog -> Magento 2 Development 13: uiComponent and di.xml

    . . .
    Discuss on Helpdesk

    Leave a Comment

    Your email address will not be published. Required fields are marked*


    Be the first to comment.

    Back to Top