Now that we have covered most of the part of admin grid. Let’s learn about forms in admin.
There are two very popular ways of creating forms in admin,
First one will be with uiComponent, this is the recommended way of creating form. 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 ui-component. And in the next blog we will create the form with block class.
First of all we need to add the edit link in the grid. We have seen in the previous blog itself about how to add the link column or the action column in admin grid. Let’s quickly create the column by following previous blog’s steps.
We will have to edit view/adminhtml/ui_component/blogmanager_blog_listing.xml file to add the column,
< ?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 name= "spinner" xsi:type= "string" > blogmanager_blog_columns < /item >
< 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 >
< 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 >
< 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 >
< 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 >
< label translate= "true" > Change status < /label >
< label translate= "true" > Enable < /label >
< url path= "blog/manage/massStatus" >
< param name= "status" > 1 < /param >
< label translate= "true" > Disable < /label >
< url path= "blog/manage/massStatus" >
< param name= "status" > 0 < /param >
< 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 >
< paging name= "listing_paging" / >
< 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 >
< column name= "entity_id" >
< filter > textRange < /filter >
< label translate= "true" > ID < /label >
< resizeDefaultWidth > 25 < /resizeDefaultWidth >
< column name= "user_name" >
< label translate= "true" > User < /label >
< label translate= "true" > Title < /label >
< column name= "content" class = "Webkul\BlogManager\Ui\Component\Listing\Columns\Content" >
< sortable > false < /sortable >
< label translate= "true" > Content < /label >
< column name= "status" component= "Magento_Ui/js/grid/columns/select" >
< options class = "Webkul\BlogManager\Model\Blog\Status" / >
< dataType > select < /dataType >
< sortable > false < /sortable >
< label translate= "true" > Status < /label >
< column name= "updated_at" component= "Magento_Ui/js/grid/columns/date" >
< filter > dateRange < /filter >
< dataType > date < /dataType >
< label translate= "true" > Updated < /label >
< column name= "created_at" component= "Magento_Ui/js/grid/columns/date" >
< filter > dateRange < /filter >
< dataType > date < /dataType >
< label translate= "true" > Created < /label >
< 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 >
< label translate= "true" > Edit < /label >
< 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 >
< label translate= "true" > Delete < /label >
Now we need to create class for the column, Ui/Component/Listing/Columns/EditAction.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
public function __construct (
ContextInterface $context,
UiComponentFactory $uiComponentFactory,
UrlInterface $urlBuilder,
$this -> urlBuilder = $urlBuilder ;
parent :: __construct ( $context, $uiComponentFactory, $components, $data ) ;
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' )] = [
'href' = > $this -> urlBuilder -> getUrl (
$urlEntityParamName = > $item[ 'entity_id' ] ,
Now you will be able to see the edit column in admin grid like below,
And now we have to create the controller as well, Controller/Adminhtml/Manage/Edit.php
namespace Webkul\BlogManager\Controller\Adminhtml\Manage;
use Magento\Backend\App\Action;
use Magento\Framework\Controller\ResultFactory;
class Edit extends Action
public function execute ()
$resultPage = $this -> resultFactory -> create ( ResultFactory :: TYPE_PAGE ) ;
$resultPage -> getConfig () -> getTitle () -> prepend ( __ ( "Edit Blog" )) ;
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,
< page xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation= "urn:magento:framework:View/Layout/etc/page_configuration.xsd" >
< referenceContainer name= "content" >
< uiComponent name= "blogmanager_blog_editing" / >
The Form ComponentNow we will create the most important file of this blog that it is the ui-component file for the form, view/adminhtml/ui_component/blogmanager_blog_editing.xml
< ?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 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 name= "template" xsi:type= "string" > templates/form/collapsible < /item >
< 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 >
< dataProvider class = "Webkul\BlogManager\Model\Blog\DataProvider" name= "blogmanager_blog_editing_data_source" >
< requestFieldName > id < /requestFieldName >
< primaryFieldName > entity_id < /primaryFieldName >
< fieldset name= "blog_data" >
< label translate= "true" > Blog Data < /label >
< 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 >
< dataType > text < /dataType >
< 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 >
< dataType > text < /dataType >
< label translate= "true" > Title < /label >
< rule name= "required-entry" xsi:type= "boolean" > true < /rule >
< 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 >
< dataType > text < /dataType >
< label translate= "true" > Content < /label >
< rule name= "required-entry" xsi:type= "boolean" > true < /rule >
< 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 >
< dataType > text < /dataType >
< label translate= "true" > Status < /label >
< options class = "Webkul\BlogManager\Model\Blog\Status" / >
You can notice the dataProvider tag inside dataSource tag it has 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 in 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 option class that we created earlier.
It won’t 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 code. 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 case, it is always good to refer to the magento’s code which you can find under /vendor/magento of root folder.
We have created the uiComponent file but we have 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.
namespace Webkul\BlogManager\Model\Blog;
use Magento\Framework\Data\OptionSourceInterface;
class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
public function __construct (
\Webkul\BlogManager\Model\ResourceModel\Blog\CollectionFactory $blogCollectionFactory,
$this -> collection = $blogCollectionFactory -> create () ;
parent :: __construct ( $name, $primaryFieldName, $requestFieldName, $meta, $data ) ;
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 the edit form like shown below.