Reading list Switch to dark mode

    Magento 2 Development 20: uiComponent form

    Updated 8 March 2024

    Now that we have covered most of the part of the admin grid. Let’s learn about forms in admin.

    There are two very popular ways of creating forms in admin,

    1. The first one will be with uiComponent, this is the recommended way of creating a form.
    2. However, in many cases, you will find that the forms are implemented with block class and widgets.

    We will see both ways but in this blog, I will show, how to create the form with the ui-component. And in the next blog, we will create the form with a block class.

    First of all, we need to add the edit link to the grid. We have seen in the previous blog itself how to add the link column or the action column in the admin grid. Let’s quickly create the column by following the previous blog’s steps.

    We will have to edit the view/adminhtml/ui_component/blogmanager_blog_listing.xml file to add the column,

    Searching for an experienced
    Magento 2 Company ?
    Find out More

    Updated code for view/adminhtml/ui_component/blogmanager_blog_listing.xml file

    <?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">
            <massaction name="listing_massaction" component="Magento_Ui/js/grid/tree-massactions">
                <argument name="data" xsi:type="array">
                    <item name="data" xsi:type="array">
                    <item name="selectProvider" xsi:type="string">blogmanager_blog_listing.blogmanager_blog_listing.blogmanager_blog_columns.ids</item>
                    <item name="displayArea" xsi:type="string">bottom</item>
                    <item name="indexField" xsi:type="string">entity_id</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="blog/manage/massDelete"/>
                        <item name="confirm" xsi:type="array">
                            <item name="title" xsi:type="string" translate="true">Delete Blogs?</item>
                            <item name="message" xsi:type="string" translate="true">Are you sure you want to delete the selected blogs?</item>
                        </item>
                    </item>
                    </argument>
                </action>
                <action name="status">
                    <settings>
                        <type>status</type>
                        <label translate="true">Change status</label>
                        <actions>
                            <action name="0">
                                <type>enable</type>
                                <label translate="true">Enable</label>
                                <url path="blog/manage/massStatus">
                                    <param name="status">1</param>
                                </url>
                            </action>
                            <action name="1">
                                <type>disable</type>
                                <label translate="true">Disable</label>
                                <url path="blog/manage/massStatus">
                                    <param name="status">0</param>
                                </url>
                            </action>
                        </actions>
                    </settings>
                </action>
            </massaction>
            <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">
            <selectionsColumn name="ids">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="indexField" xsi:type="string">entity_id</item>
                    </item>
                </argument>
            </selectionsColumn>
            <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>
            <actionsColumn name="edit_action" class="Webkul\BlogManager\Ui\Component\Listing\Columns\EditAction">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="indexField" xsi:type="string">entity_id</item>
                        <item name="viewUrlPath" xsi:type="string">blogmanager/manage/edit</item>
                        <item name="urlEntityParamName" xsi:type="string">id</item>
                        <item name="sortOrder" xsi:type="number">40</item>
                    </item>
                </argument>
                <settings>
                    <label translate="true">Edit</label>
                </settings>
            </actionsColumn>
            <actionsColumn name="delete_action" class="Webkul\BlogManager\Ui\Component\Listing\Columns\DeleteAction">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="indexField" xsi:type="string">entity_id</item>
                        <item name="viewUrlPath" xsi:type="string">blogmanager/manage/delete</item>
                        <item name="urlEntityParamName" xsi:type="string">id</item>
                        <item name="sortOrder" xsi:type="number">50</item>
                    </item>
                </argument>
                <settings>
                    <label translate="true">Delete</label>
                </settings>
            </actionsColumn>
        </columns>
    </listing>

    Now we need to create a class for the column, Ui/Component/Listing/Columns/EditAction.php

    <?php
    namespace Webkul\BlogManager\Ui\Component\Listing\Columns;
    
    use Magento\Framework\UrlInterface;
    use Magento\Framework\View\Element\UiComponent\ContextInterface;
    use Magento\Framework\View\Element\UiComponentFactory;
    
    class EditAction extends \Magento\Ui\Component\Listing\Columns\Column
    {
        /**
         * @var Magento\Framework\UrlInterface
         */
        protected $urlBuilder;
    
        /**
         * Dependency Initilization
         *
         * @param ContextInterface $context
         * @param UiComponentFactory $uiComponentFactory
         * @param UrlInterface $urlBuilder
         * @param array $components
         * @param array $data
         */
        public function __construct(
            ContextInterface $context,
            UiComponentFactory $uiComponentFactory,
            UrlInterface $urlBuilder,
            array $components = [],
            array $data = []
        ) {
            $this->urlBuilder = $urlBuilder;
            parent::__construct($context, $uiComponentFactory, $components, $data);
        }
    
        /**
         * Prepare Data Source
         *
         * @param array $dataSource
         * @return array
         */
        public function prepareDataSource(array $dataSource)
        {
            if (isset($dataSource['data']['items'])) {
                foreach ($dataSource['data']['items'] as &$item) {
                    if (isset($item['entity_id'])) {
                        $viewUrlPath = $this->getData('config/viewUrlPath');
                        $urlEntityParamName = $this->getData('config/urlEntityParamName');
                        $item[$this->getData('name')] = [
                            'view' => [
                                'href' => $this->urlBuilder->getUrl(
                                    $viewUrlPath,
                                    [
                                        $urlEntityParamName => $item['entity_id'],
                                    ]
                                ),
                                'label' => __('Edit'),
                            ],
                        ];
                    }
                }
            }
            return $dataSource;
        }
    }

    Now you will be able to see the edit column in the admin grid like below,

    Image showing edit column on Admin end.

    And now we have to create the controller as well, Controller/Adminhtml/Manage/Edit.php

    Code for Controller/Adminhtml/Manage/Edit.php file

    <?php
    namespace Webkul\BlogManager\Controller\Adminhtml\Manage;
    
    use Magento\Backend\App\Action;
    use Magento\Framework\Controller\ResultFactory;
    
    class Edit extends Action
    {
        /**
         * Provides content
         *
         * @return \Magento\Framework\View\Result\Page
         */
        public function execute()
        {
            $resultPage = $this->resultFactory->create(ResultFactory::TYPE_PAGE);
            $resultPage->getConfig()->getTitle()->prepend(__("Edit Blog"));
            return $resultPage;
        }
    
        /**
         * Check Autherization
         *
         * @return boolean
         */
        public function _isAllowed()
        {
            return $this->_authorization->isAllowed('Webkul_BlogManager::edit');
        }
    }

    If you remember, how we created the admin grid with ui-component, then it should come automatically to you that we need to create a layout file and then we will have to create the ui-component file.

    The layout file will be view/adminhtml/layout/blogmanager_manage_edit.xml based on the URL,

    Code for view/adminhtml/layout/blogmanager_manage_edit.xml file

    <?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>
            <referenceContainer name="content">
                <uiComponent name="blogmanager_blog_editing"/>
            </referenceContainer>
        </body>
    </page>

    The Form Component

    Now we will create the most important file of this blog which is the ui-component file for the form, view/adminhtml/ui_component/blogmanager_blog_editing.xml

    Code for view/adminhtml/ui_component/blogmanager_blog_editing.xml file

    <?xml version="1.0" encoding="UTF-8"?>
    <form 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_editing.blogmanager_blog_editing_data_source</item>
                <item name="deps" xsi:type="string">blogmanager_blog_editing.blogmanager_blog_editing_data_source</item>
            </item>
            <item name="label" xsi:type="string" translate="true">Blog Data</item>
            <item name="config" xsi:type="array">
                <item name="dataScope" xsi:type="string">data</item>
                <item name="namespace" xsi:type="string">blogmanager_blog_editing</item>
            </item>
            <item name="template" xsi:type="string">templates/form/collapsible</item>
        </argument>
        <dataSource name="blogmanager_blog_editing_data_source">
            <argument name="data" xsi:type="array">
                <item name="js_config" xsi:type="array">
                    <item name="component" xsi:type="string">Magento_Ui/js/form/provider</item>
                </item>
            </argument>
            <dataProvider class="Webkul\BlogManager\Model\Blog\DataProvider" name="blogmanager_blog_editing_data_source">
                <settings>
                    <requestFieldName>id</requestFieldName>
                    <primaryFieldName>entity_id</primaryFieldName>
                </settings>
            </dataProvider>
        </dataSource>
        <fieldset name="blog_data">
            <settings>
                <label translate="true">Blog Data</label>
            </settings>
            <field name="entity_id" formElement="input">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="source" xsi:type="string">blog</item>
                    </item>
                </argument>
                <settings>
                    <dataType>text</dataType>
                    <visible>false</visible>
                </settings>
            </field>
            <field name="title" formElement="input">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="source" xsi:type="string">blog</item>
                    </item>
                </argument>
                <settings>
                    <dataType>text</dataType>
                    <label translate="true">Title</label>
                    <validation>
                        <rule name="required-entry" xsi:type="boolean">true</rule>
                    </validation>
                </settings>
            </field>
            <field name="content" formElement="textarea">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="source" xsi:type="string">blog</item>
                    </item>
                </argument>
                <settings>
                    <dataType>text</dataType>
                    <label translate="true">Content</label>
                    <validation>
                        <rule name="required-entry" xsi:type="boolean">true</rule>
                    </validation>
                </settings>
            </field>
            <field name="status" formElement="select">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="source" xsi:type="string">blog</item>
                    </item>
                </argument>
                <settings>
                    <dataType>text</dataType>
                    <label translate="true">Status</label>
                </settings>
                <formElements>
                    <select>
                        <settings>
                            <options class="Webkul\BlogManager\Model\Blog\Status"/>
                        </settings>
                    </select>
                </formElements>
            </field>
        </fieldset>
    </form>

    You can notice the dataProvider tag inside the dataSource tag it has a class associated with it which will be responsible for providing the data for the form based on the blog id. It will get the blog id from the URL based on the value in requestFieldName and primaryFieldName will be used to load the model.

    We can add multiple group of fields with multiple fieldset tag. One use case you can see on the product add/edit page.
    We add different fields with field tag and we can configure them as we want in the tag itself. Also please notice for the status field, how we have provided the options with the option class that we created earlier.

    It won’t be possible or practical to explain each and every part of this XML file. And as I said earlier, most of the time you will end up copy-pasting these codes. If you want an in-depth explanation then you can always refer to the magento’s devdoc. As of now, I found many things missing from the devdoc itself. In such cases, it is always good to refer to the Magento’s code which you can find under the /vendor/magento folder of the root directory.

    We have created the uiComponent file but we still have one more file to create. And that file is Model/Blog/DataProvider.php which is responsible for providing the data for the form.

    Code for Model/Blog/DataProvider.php file

    <?php
    namespace Webkul\BlogManager\Model\Blog;
    
    use Magento\Framework\Data\OptionSourceInterface;
    
    class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
    {
        /**
         * @var \Webkul\BlogManager\Model\ResourceModel\Blog\Collection
         */
        protected $collection;
    
        /**
         * @var array
         */
        protected $loadedData;
    
        /**
         * Dependency Initilization
         *
         * @param [type] $name
         * @param [type] $primaryFieldName
         * @param [type] $requestFieldName
         * @param \Webkul\BlogManager\Model\ResourceModel\Blog\CollectionFactory $blogCollectionFactory
         * @param array $meta
         * @param array $data
         */
        public function __construct(
            $name,
            $primaryFieldName,
            $requestFieldName,
            \Webkul\BlogManager\Model\ResourceModel\Blog\CollectionFactory $blogCollectionFactory,
            array $meta = [],
            array $data = []
        ) {
            $this->collection = $blogCollectionFactory->create();
            parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data);
        }
    
        /**
         * Get Data
         *
         * @return array
         */
        public function getData()
        {
            if (isset($this->loadedData)) {
                return $this->loadedData;
            }
            $items = $this->collection->getItems();
            foreach ($items as $blog) {
                $this->loadedData[$blog->getId()] = $blog->getData();
            }
            return $this->loadedData;
        }
    }

    The getData method will provide the data that is the model for the blog. The collection will be filtered based on the requestFieldName and primaryFieldName that we have passed in the parent’s constructor.

    Now when you click on the edit link, you should see the edit form as shown below.

    Image showing Edit Blog page


    Next Blog -> Magento 2 Development 21: Form Widget

    Previous Blog -> Magento 2 Development 19: Action Column

    . . .

    Leave a Comment

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


    Be the first to comment.

    Back to Top

    Message Sent!

    If you have more details or questions, you can reply to the received confirmation email.

    Back to Home