How to Create a Magento 2 Admin Grid with a Custom Form

Magento 2 Admin Grid

In this article, we will show you how to create a custom Magento 2 Admin Grid. Magento 2 Grid is a visualization of your custom database table. The admin grid can contain various options, e.g., filters, sorting, actions over multiple rows, etc. We will use a custom form to add data to our database table.

In order to do this, you will have to create/add:

  1. Basic Magento 2 module
  2. Database table
  3. Admin menu link
  4. Grid page with options
  5. Form page

In this example, we will be using one of our modules for managing Brands from the grid, where <Vendor> is SyncIt and <module> is Brand.

Creating a Basic Magento 2 Module

The process of creating a basic Magento 2 module is very simple since you need to create only 2 essential files:

<Vendor>/<module>/registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
   \Magento\Framework\Component\ComponentRegistrar::MODULE,
   'SyncIt_Brand',
   __DIR__
);

<Vendor>/<module>/etc/module.xml

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
  <module name="SyncIt_Brand" setup_version="1.0.0"/>
</config>

After you have created the basic Magento 2 module you can proceed to the next step.

Creating a Database Table

For Magento versions newer than 2.3 use method #1 and for older versions use method #2.

Method #1:
 
You need to create db_schema.xml at <Vendor>/<module>/etc/db_schema.xml.

<?xml version="1.0" ?>
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
  <table comment="syncit_brand_brand Table" engine="innodb" name="syncit_brand_brand" resource="default">
     <column name="id" nullable="false" padding="6" comment="Brand ID" unsigned="true" identity="true" xsi:type="smallint"/>
     <column name="brand_name" nullable="false" length="255" comment="Brand Name" xsi:type="varchar"/>
     <constraint referenceId="PRIMARY" xsi:type="primary">
        <column name="id"/>
     </constraint>
     <index referenceId="SYNCIT_BRAND_NAME" indexType="fulltext">
        <column name="brand_name"/>
     </index>
  </table>
</schema>

Method #2:

You need to create InstallSchema.php at <Vendor>/<module>/Setup/InstallSchema.php.

<?php
namespace SyncIt\Brand\Setup;

use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\DB\Ddl\Table;
use Magento\Framework\Setup\InstallSchemaInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\SchemaSetupInterface;

/**
* @codeCoverageIgnore
*/
class InstallSchema implements InstallSchemaInterface
{
   /**
    * {@inheritdoc}
    * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
    */
   public function install(SchemaSetupInterface $setup, ModuleContextInterface $context)
   {
       $installer = $setup;
       $installer->startSetup();

       /**
        * Create table 'syncit_store_locator'
        */
       $table = $setup->getConnection()
           ->newTable($setup->getTable('syncit_brand_brand'))
           ->addColumn(
               'id',
               Table::TYPE_INTEGER,
               null,
               ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true],
               'Brand ID'
           )
           ->addColumn(
               ‘brand_name’,
               Table::TYPE_TEXT,
               255,
               [],
               'Brand Name'
           )

           ->addIndex(
               $installer->getIdxName(
                   'syncit_brand_brand',
                   [‘brand_name’],
                   AdapterInterface::INDEX_TYPE_UNIQUE
               ),
               [‘brand_name’],
               ['type' => AdapterInterface::INDEX_TYPE_UNIQUE]
           );
       $setup->getConnection()->createTable($table);
$installer->endSetup();
   }
}

Now that you have created your database table you can create a menu link in the Admin panel and admin route.

Adding an Admin Menu Link

For the menu link, you need to create menu.xml at <Vendor>/<module>/etc/adminhtml/menu.xml.

<?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>
     <!-- Main menu -->
     <add id="SyncIt_Core::syncit"
         title="SyncIt Group"
         translate="title"
         module="SyncIt_Core"
         sortOrder="50"
         resource="Magento_Backend::content"
     />
     <!-- Main menu Title -->
     <add id="SyncIt_Brand::syncit_general"
         title="Brand Settings"
         translate="title"
         module="SyncIt_Brand"
         sortOrder="60"
         parent="SyncIt_Core::syncit"
         resource="Magento_Backend::content"
     />
     <!-- Sub menu items -->
     <add id="SyncIt_Brand::syncit_brand_brand"
         title="Manage Brands"
         module="SyncIt_Brand"
         translate="title"
         sortOrder="30"
         resource="Magento_Backend::content"
         parent="SyncIt_Brand::syncit_general"
         action="syncit_brand/brand/index/"
     />
  </menu>
</config>

For the admin route, you need to create routes.xml at <Vendor>/<module>/etc/adminhtml/routes.xml.

<?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 frontName="syncit_brand" id="syncit_brand">
        <module before="Magento_Backend" name="SyncIt_Brand"/>
     </route>
  </router>
</config>

Adding a Grid Page with Options

For the Grid page, you need to create the controller Index.php at 

<Vendor>/<module>/Controller/Adminhtml/Brand/Index.php.

<?php

namespace SyncIt\Brand\Controller\Adminhtml\Brand;

use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\View\Result\PageFactory;

/**
* Class Index
*
* @package SyncIt\Brand\Controller\Adminhtml\Brand
*/
class Index extends Action
{
   protected $resultPageFactory;

   /**
    * Constructor
    *
    * @param \Magento\Backend\App\Action\Context        $context
    * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
    */
   public function __construct(
       Context $context,
       PageFactory $resultPageFactory
   ) {
       $this->resultPageFactory = $resultPageFactory;
       parent::__construct($context);
   }

   /**
    * Index action
    *
    * @return \Magento\Framework\Controller\ResultInterface
    */
   public function execute()
   {
       $resultPage = $this->resultPageFactory->create();
       $resultPage->getConfig()->getTitle()->prepend(__("Brand"));
       return $resultPage;
   }
}

Now that you have added the grid page, you need to set a layout for that page.

The Layout File

Firstly, you need to create a layout file.

<Vendor>/<module>/view/adminhtml/layout/syncit_brand_brand_index.xml

<?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">
  <update handle="styles"/>
  <body>
     <referenceContainer name="content">
        <uiComponent name="syncit_brand_brand_listing"/>
     </referenceContainer>
  </body>
</page>

As was said, in this layout, you need a uiComponent with the name syncit_brand_brand_listing. With the above controller, you have created the page. But, with this uiComponent, you are going to define what appears on the page. This uiComponent needs to be created at the following location: 

<Vendor>/<module>/view/adminhtml/ui_component/syncit_brand_brand_listing.xml

<?xml version="1.0" ?>
<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">syncit_brand_brand_listing.syncit_brand_brand_listing_data_source</item>
     </item>
  </argument>
  <settings>
     <spinner>syncit_brand_brand_columns</spinner>
     <deps>
        <dep>syncit_brand_brand_listing.syncit_brand_brand_listing_data_source</dep>
     </deps>
     <buttons>
        <button name="add">
           <url path="*/*/new"/>
           <class>primary</class>
           <label translate="true">Add new Brand</label>
        </button>
     </buttons>
  </settings>
  <dataSource name="syncit_brand_brand_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">syncit_brand_brand_listing_data_source</argument>
        <argument name="primaryFieldName" xsi:type="string">id</argument>
        <argument name="requestFieldName" xsi:type="string">id</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>
  <columns name="syncit_brand_brand_columns">
     <selectionsColumn name="ids">
        <argument name="data" xsi:type="array">
           <item name="config" xsi:type="array">
              <item name="resizeEnabled" xsi:type="boolean">false</item>
              <item name="resizeDefaultWidth" xsi:type="string">55</item>
              <item name="indexField" xsi:type="string">id</item>
              <item name="sortOrder" xsi:type="number">1</item>
           </item>
        </argument>
     </selectionsColumn>
     <column name="id">
        <argument name="data" xsi:type="array">
           <item name="config" xsi:type="array">
              <item name="filter" xsi:type="string">textRange</item>
              <item name="sorting" xsi:type="string">asc</item>
              <item name="label" xsi:type="string" translate="true">ID</item>
              <item name="sortOrder" xsi:type="number">2</item>
           </item>
        </argument>
     </column>

     <column name="brand_name">
        <argument name="data" xsi:type="array">
           <item name="config" xsi:type="array">
              <item name="filter" xsi:type="string">text</item>
              <item name="editor" xsi:type="array">
                 <item name="validation" xsi:type="array">
                    <item name="required-entry" xsi:type="boolean">true</item>
                 </item>
              </item>
              <item name="label" xsi:type="string" translate="true">Brand</item>
              <item name="sortOrder" xsi:type="number">3</item>
           </item>
        </argument>
     </column>
  </columns>
</listing>

The <listingToolbar> Element

If you want to add some actions over the grid you will need the <listingToolbar> element:

  <listingToolbar name="listing_top">
     <settings>
        <sticky>true</sticky>
     </settings>
  </listingToolbar>

As it was mentioned at the beginning of this article, you can add actions over the grid, e.g., a filter, search, export, mass action, etc. So, now we will show you how to add those actions.

All of these actions are put inside the <listingToolbar> block. You can add a bookmark option for when you want to save filters for future use.

Further Grid Customization

The bookmark option can be added with the following line:

<bookmark name="bookmarks"/>

If you add the following code, you can edit which columns appear in the grid.

<columnsControls name="columns_controls"/>

Filtering the grid is possible if you add this code:

<filters name="listing_filters"/>

For the search functionality, the following code should be added:

<filterSearch name="fulltext"/>

To add a pager for your grid, add this line of code: 

<paging name="listing_paging"/>

There is also an option for exporting all of your grid data, which can be enabled with the following code:

<exportButton name="export_button"/>

Multiple Grid Rows

And last but not least, you can add an option for actions over multiple grid rows. In this example, you will only add a Delete option but you can add whatever your requirements are:

<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="*/*/MassDelete"/>
           <item name="confirm" xsi:type="array">
              <item name="title" xsi:type="string" translate="true">Delete</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>

In order for this to work, you will need a controller named MassDelete.php. It will process which rows you want to delete. That controller should be placed at the following location:

<Vendor>/<module>/Controller/Adminhtml/Brand/massDelete.php

Magento 2.3

For Magento versions 2.3 and above you can use the code below:

<?php

namespace SyncIt\Brand\Controller\Adminhtml\Brand;

use Exception;
use Magento\Backend\App\Action;
use Magento\Framework\Controller\ResultFactory;
use Magento\Backend\App\Action\Context;
use SyncIt\Brand\Model\ResourceModel\Brand\Collection as Brand;

/**
* Class MassDelete
*
* @package SyncIt\Brand\Controller\Adminhtml\Brand
*/
class MassDelete extends Action
{

   /**
    * @var Brand
    */
   protected $brand;


   /**
    * @param Context $context
    * @param Brand $brand
    */
   public function __construct(Context $context, Brand $brand)
   {
       parent::__construct($context);
       $this->brand = $brand;
   }

   /**
    * Execute action
    *
    * @return \Magento\Backend\Model\View\Result\Redirect
    */
   public function execute()
   {
       $selectedIds = $this->getRequest()->getParams()['selected'];
       if (!is_array($selectedIds)) {
           $this->messageManager->addErrorMessage(__('Please select one or more brand.'));
       } else {
           try {
               $collectionSize = count($selectedIds);
               foreach ($selectedIds as $_id) {
                   $brand = $this->brand->getItems()[$_id];
                   $brand->delete();
               }
               $this->messageManager->addSuccessMessage(__('A total of %1 record(s) have been deleted.', $collectionSize));
           } catch (Exception $e) {
               $this->messageManager->addErrorMessage($e->getMessage());
           }
       }

       /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
       $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
       return $resultRedirect->setPath('*/*/');
   }
}

Earlier Magento Versions

For earlier Magento versions you need to change the if statement in execute() function a little bit because Magento was passing the excluded parameter instead of the selected. So, you need to manually filter the collection by search params and by filter params.

This bug only occurs if you select all rows. In that case, Magento returns $selectedIds as null, so that’s why you should implement delete logic inside this if statement.

So, for mass action to work you need to change this if statement: 

 if (!is_array($selectedIds)) {
           $this->messageManager->addErrorMessage(__('Please select one or more brand.'));
       }

With this:

if (!is_array($selectedIds)) {
   $brandCollection = $this->_objectManager->create('SyncIt/Brand/Model/ResourceModel/Brand/Collection');
   $filterParam = $this->getRequest()->getParam("filters");
   //filter collection by filters
   foreach($filterParam as $fKey => $fParam) {
       if($fKey == "placeholder") {
           continue;
       }
       $brandCollection->addFieldToFilter($fKey, ["like" => "%".$fParam."%"]);
   }

   //get search column/s
   $searchArrays[] = 'brand_name';
   $queryArray = [];
   //filter search param
   $searchParam = $this->getRequest()->getParam("search");
   if(isset($searchParam) && !empty($searchParam)) {
       $queryArray[] = $searchParam;
       $brandCollection->addFieldToFilter($searchArrays, $queryArray);
   }

   //delete brand
   foreach($brandCollection->getItems() as $brandItem) {
       try{
           $brandItem->delete();
           $this->messageManager->addSuccessMessage(__('Brand with Id deleted: ' . $brandItem->getData('id')));
       } catch (\Exception $e) {
           $this->messageManager->addErrorMessage($e->getMessage());
           $this->messageManager->addErrorMessage(__('Error for: ' . $brandItem->getData("id")));
       }
   }
}

The Result

So, that covers the grid page. This is how it should look like. 

Magento 2 Grid

Now, let’s move on to the form page. We will add some new data to the database table that will be shown in our admin grid.

Adding a Form Page

For the form page, you need to create layout XML. If you want to add the new items you need syncit_brand_brand_new.xml at:

<Vendor>/<module>/view/adminhtml/layout/syncit_brand_brand_new.xml

<?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">
  <update handle="styles"/>
  <body>
     <referenceContainer name="content">
        <uiComponent name="syncit_brand_brand_form"/>
     </referenceContainer>
  </body>
</page>

This layout file points to uiComponent syncit_brand_brand_form, which is a uiComponent layout XML file that defines the form.

<Vendor>/<module>/view/adminhtml/ui_component/syncit_brand_brand_form.xml

<?xml version="1.0" ?>
<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">syncit_brand_brand_form.brand_form_data_source</item>
     </item>
     <item name="label" translate="true" xsi:type="string">General Information</item>
     <item name="template" xsi:type="string">templates/form/collapsible</item>
  </argument>
  <settings>
     <buttons>
        <button class="SyncIt\Brand\Block\Adminhtml\Brand\Edit\BackButton" name="back"/>
        <button class="SyncIt\Brand\Block\Adminhtml\Brand\Edit\DeleteButton" name="delete"/>
        <button class="SyncIt\Brand\Block\Adminhtml\Brand\Edit\SaveButton" name="save"/>
        <button class="SyncIt\Brand\Block\Adminhtml\Brand\Edit\SaveAndContinueButton" name="save_and_continue"/>
     </buttons>
     <namespace>syncit_brand_brand_form</namespace>
     <dataScope>data</dataScope>
     <deps>
        <dep>syncit_brand_brand_form.brand_form_data_source</dep>
     </deps>
  </settings>
  <dataSource name="brand_form_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>
     <settings>
        <submitUrl path="*/*/save"/>
     </settings>
     <dataProvider class="SyncIt\Brand\Model\Brand\DataProvider" name="brand_form_data_source">
        <settings>
           <requestFieldName>id</requestFieldName>
           <primaryFieldName>id</primaryFieldName>
        </settings>
     </dataProvider>
  </dataSource>
  <fieldset name="general">
     <settings>
        <label/>
     </settings>

     <field formElement="input" name="brand" sortOrder="10">
        <argument name="data" xsi:type="array">
           <item name="config" xsi:type="array">
              <item name="source" xsi:type="string">Brand</item>
           </item>
        </argument>
        <settings>
           <dataType>text</dataType>
           <label translate="true">Brand name</label>
           <dataScope>brand</dataScope>
           <validation>
              <rule name="required-entry" xsi:type="boolean">false</rule>
           </validation>
        </settings>
     </field>
  </fieldset>
</form>

The <buttons> section

The <buttons> section lists all buttons that will be available at the top right corner for which you need to create a Block.

Firstly, you need to create GenericButton.php which you will extend for any button you need.

<Vendor>/<module>/Block/Adminhtml/Brand/Edit/GenericButton.php

<?php

namespace SyncIt\Brand\Block\Adminhtml\Brand\Edit;

use Magento\Backend\Block\Widget\Context;

/**
* Class GenericButton
*
* @package SyncIt\Brand\Block\Adminhtml\Brand\Edit
*/
abstract class GenericButton
{

   protected $context;

   /**
    * @param \Magento\Backend\Block\Widget\Context $context
    */
   public function __construct(Context $context)
   {
       $this->context = $context;
   }

   /**
    * Return model ID
    *
    * @return int|null
    */
   public function getModelId()
   {
       return $this->context->getRequest()->getParam('id');
   }

   /**
    * Generate url by route and parameters
    *
    * @param  string $route
    * @param  array  $params
    * @return string
    */
   public function getUrl($route = '', $params = [])
   {
       return $this->context->getUrlBuilder()->getUrl($route, $params);
   }
}

Then, you need to create SaveButton.php.

<Vendor>/<module>/Block/Adminhtml/Brand/Edit/SaveButton.php

<?php

namespace SyncIt\Brand\Block\Adminhtml\Brand\Edit;

use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface;

/**
* Class SaveButton
*
* @package SyncIt\Brand\Block\Adminhtml\Brand\Edit
*/
class SaveButton extends GenericButton implements ButtonProviderInterface
{

   /**
    * @return array
    */
   public function getButtonData()
   {
       return [
           'label' => __('Save Brand'),
           'class' => 'save primary',
           'data_attribute' => [
               'mage-init' => ['button' => ['event' => 'save']],
               'form-role' => 'save',
           ],
           'sort_order' => 90,
       ];
   }
}

And finally, you need Save.php which will handle the actual saving of the new entry.

<Vendor>/<module>/Controller/Adminhtml/Brand/Save.php

<?php

namespace SyncIt\Brand\Controller\Adminhtml\Brand;

use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\App\Request\DataPersistorInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Catalog\Api\CategoryRepositoryInterface;
use Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory;
use SyncIt\Brand\Model\Brand;
use SyncIt\Brand\Model\ResourceModel\Brand\Collection;

/**
* Class Save
*
* @package SyncIt\Brand\Controller\Adminhtml\Brand
*/
class Save extends Action
{
   /**
    * @var CategoryRepositoryInterface
    */
   protected $categoryRepository;
   /**
    * @var \Magento\Framework\App\Request\DataPersistorInterface
    */
   protected $dataPersistor;
   /**
    * @var \Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory
    */
   protected $attributeFactory;

   /**
    * @param \Magento\Backend\App\Action\Context                       $context
    * @param \Magento\Framework\App\Request\DataPersistorInterface     $dataPersistor
    * @param \Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory $attributeFactory
    * @param \Magento\Catalog\Api\CategoryRepositoryInterface          $categoryRepository
    */
   public function __construct(
       Context $context,
       DataPersistorInterface $dataPersistor,
       AttributeFactory $attributeFactory,
       CategoryRepositoryInterface $categoryRepository
   ) {
       $this->dataPersistor = $dataPersistor;
       $this->attributeFactory = $attributeFactory;
       $this->categoryRepository = $categoryRepository;
       parent::__construct($context);
   }

   /**
    * Save action
    *
    * @return \Magento\Framework\Controller\ResultInterface
    * @throws \Magento\Framework\Exception\LocalizedException
    */
   public function execute()
   {
       /**
        * @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect
        */
       $resultRedirect = $this->resultRedirectFactory->create();
       $data = $this->getRequest()->getPostValue();
       if ($data) {
           $id = $this->getRequest()->getParam('id');
      
           $model = $this->_objectManager->create(Brand::class)->load($id);
           if (!$model->getId() && $id) {
               $this->messageManager->addErrorMessage(__('This Brand no longer exists.'));
               return $resultRedirect->setPath('*/*/');
           }

           $attr = $this->attributeFactory->create()->loadByCode('catalog_product', 'brand');
           if ($attr->usesSource()) {
               $brandName = $attr->getSource()->getOptionText($data['brand']);
               $model->setData('brand_name', $brandName);
           }

           try {
               $model->save();
               $this->messageManager->addSuccessMessage(__('You saved the Brand.'));
               $this->dataPersistor->clear('syncit_brand_brand');
      
               if ($this->getRequest()->getParam('back')) {
                   return $resultRedirect->setPath('*/*/edit', ['id' => $model->getId()]);
               }
               return $resultRedirect->setPath('*/*/');
           } catch (LocalizedException $e) {
               $this->messageManager->addErrorMessage($e->getMessage());
           } catch (\Exception $e) {
               $this->messageManager->addExceptionMessage($e, __('Something went wrong while saving the Brand.'));
           }
      
           $this->dataPersistor->set('syncit_brand_brand', $data);
           return $resultRedirect->setPath('*/*/edit', ['id' => $this->getRequest()->getParam('id')]);
       }
       return $resultRedirect->setPath('*/*/');
   }
}

Editor’s Note: Please note that the code shown in this blog post is not completed. It is up to the developer to finish the code. 

The Result

This is how the form page should look like.

Custom Magento 2 admin grid form

Wrap Up

So, this is how you create an admin grid with a custom form. In conclusion, this is a very convenient way of showing data from a database and adding some new content to the database.

Of course, if you need any help with Magento 2 development, do not hesitate to contact us at [email protected]

Source

Magento 2 Development Documentation

5 1 vote
Article Rating
Subscribe
Notify of
guest
2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
shoaib
shoaib
3 years ago

Add New Buttong Redirecting to the admin Dashboard and giving error “Invalid security or form key. Please refresh the page.

Đurđica Ilić
Editor
Đurđica Ilić
2 years ago
Reply to  shoaib

Can you please share your //view/adminhtml/ui_component/*_listing.xml?