Magento 2.2 Admin – Create and Add Backend Form to Custom Admin Grid

adminadminformmagento2.2PHP

I have created admin grid for Image Slider in backend and need to add backend form for that grid.

If I click Add New slide or edit button, it needs to show a form. So Suggest me, how to create a backend form and how to link it with the grid?

Best Answer

If you just need to create an admin form, have a look at here.

https://www.pierrefay.com/magento2-training/form-component-backend-crud-admin.html

To create our Form, we will first create the newAction action in our controller like this:

Pfay/Contacts/Controller/Adminhtml/Contact/NewAction.php

<?php
namespace Pfay\Contacts\Controller\Adminhtml\Test;
use Magento\Backend\App\Action;
use Pfay\Contacts\Model\Contact as Contact;

class NewAction extends \Magento\Backend\App\Action
{
    /**
     * Edit A Contact Page
     *
     * @return \Magento\Backend\Model\View\Result\Page|\Magento\Backend\Model\View\Result\Redirect
     * @SuppressWarnings(PHPMD.NPathComplexity)
     */
    public function execute()
    {
        $this->_view->loadLayout();
        $this->_view->renderLayout();

        $contactDatas = $this->getRequest()->getParam('contact');
        if(is_array($contactDatas)) {
            $contact = $this->_objectManager->create(Contact::class);
            $contact->setData($contactDatas)->save();
            $resultRedirect = $this->resultRedirectFactory->create();
            return $resultRedirect->setPath('*/*/index');
        }
    }
}

We load and then display the layout that will contain the form. We check if we receive the parameter "contact" (if the form is sent), if yes then we save the contact in the database . Logically, we will now create the layout

Pfay/Contacts/view/adminhtml/layout/contacts_test_newaction.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="contacts_test_edit"/>
    <body/>
</page>

In this layout, we just tell him to look for our layout contacts_text_edit. We create the layout file for editing

Pfay/Contacts/view/adminhtml/layout/contacts_test_edit.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"/>
    <update handle="editor"/>
    <body>
        <referenceContainer name="content">
            <uiComponent name="pfay_contacts_form"/>
        </referenceContainer>
    </body>
</page>

Creating the file uiComponent for creation our form in magento2 Here it is said to load a uiComponent named "pfay_contacts_form", ( remember we did the same for the grid in the previous tutorial). We will, therefore, create the form in this uiComponent form. So let's create our uiComponent file for our form

app/code/Pfay/Contacts/view/adminhtml/ui_component/pfay_contacts_form.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">pfay_contacts_form.contacts_form_data_source</item>
            <item name="deps" xsi:type="string">pfay_contacts_form.contacts_form_data_source</item>
        </item>
        <item name="label" xsi:type="string" translate="true">Sample Form</item>
        <item name="layout" xsi:type="array">
            <item name="type" xsi:type="string">tabs</item>
        </item>

        <item name="buttons" xsi:type="array">
            <item name="back" xsi:type="string">Pfay\Contacts\Block\Adminhtml\Contact\Edit\BackButton</item>
            <item name="delete" xsi:type="string">Pfay\Contacts\Block\Adminhtml\Contact\Edit\DeleteButton</item>
            <item name="reset" xsi:type="string">Pfay\Contacts\Block\Adminhtml\Contact\Edit\ResetButton</item>
            <item name="save" xsi:type="string">Pfay\Contacts\Block\Adminhtml\Contact\Edit\SaveButton</item>
        </item>
    </argument>

    <dataSource name="contacts_form_data_source">
        <argument name="dataProvider" xsi:type="configurableObject">
            <argument name="class" xsi:type="string">Pfay\Contacts\Model\Contact\DataProvider</argument>
            <argument name="name" xsi:type="string">contacts_form_data_source</argument>
            <argument name="primaryFieldName" xsi:type="string">pfay_contacts_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/form/provider</item>
            </item>
        </argument>
    </dataSource>

    <fieldset name="contact">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="label" xsi:type="string" translate="true">Sample Fieldset</item>
            </item>
        </argument>

        <!-- This field represents form id and is hidden -->
        <field name="pfay_contact_id">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="visible" xsi:type="boolean">false</item>
                    <item name="dataType" xsi:type="string">text</item>
                    <item name="formElement" xsi:type="string">input</item>
                    <item name="source" xsi:type="string">contact</item>
                </item>
            </argument>
        </field>

        <!-- This field has data type 'text' and standard 'input' form element and looks like input -->
        <field name="name">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="label" xsi:type="string">Name</item>
                    <item name="visible" xsi:type="boolean">true</item>
                    <item name="dataType" xsi:type="string">text</item>
                    <item name="formElement" xsi:type="string">input</item>
                    <item name="source" xsi:type="string">contact</item>
                </item>
            </argument>
        </field>


        <!-- This field has data type 'text' and standard 'input' form element and looks like input -->
        <field name="email">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="label" xsi:type="string">Email</item>
                    <item name="visible" xsi:type="boolean">true</item>
                    <item name="dataType" xsi:type="string">text</item>
                    <item name="formElement" xsi:type="string">input</item>
                    <item name="source" xsi:type="string">contact</item>
                </item>
            </argument>
        </field>

    </fieldset>
</form>

The datasource of our magento2 form takes here our class "Pfay\Contacts\Model\Contact\DataProvider" so we will create it. So create

app/code/Pfay/Contacts/Model/Contact/DataProvider.php

<?php
namespace Pfay\Contacts\Model\Contact;

use Pfay\Contacts\Model\ResourceModel\Contact\CollectionFactory;
use Pfay\Contacts\Model\Contact;

class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
{
    /**
     * @param string $name
     * @param string $primaryFieldName
     * @param string $requestFieldName
     * @param CollectionFactory $contactCollectionFactory
     * @param array $meta
     * @param array $data
     */
    public function __construct(
        $name,
        $primaryFieldName,
        $requestFieldName,
        CollectionFactory $contactCollectionFactory,
        array $meta = [],
        array $data = []
    ) {
        $this->collection = $contactCollectionFactory->create();
        parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data);
    }

    public function getData()
    {
        if (isset($this->loadedData)) {
            return $this->loadedData;
        }

        $items = $this->collection->getItems();
        $this->loadedData = array();
        /** @var Contact $contact */
        foreach ($items as $contact) {
            // our fieldset is called "contact" or this table so that magento can find its datas:
            $this->loadedData[$contact->getId()]['contact'] = $contact->getData();
        }

        return $this->loadedData;

    }
}

It is this file that allows our fields to be automatically mapped to the database. The so-called "dataBinding". Here we called our fieldset "contact", so we pass our Contact object in the loadedData array that we return. Configuring our form buttons Under magento2, in the forms, we define classes for buttons like what we did in our uiComponent:

 <item name="buttons" xsi:type="array">
        <item name="back" xsi:type="string">Pfay\Contacts\Block\Adminhtml\Contact\Edit\BackButton</item>
        <item name="delete" xsi:type="string">Pfay\Contacts\Block\Adminhtml\Contact\Edit\DeleteButton</item>
        <item name="reset" xsi:type="string">Pfay\Contacts\Block\Adminhtml\Contact\Edit\ResetButton</item>
        <item name="save" xsi:type="string">Pfay\Contacts\Block\Adminhtml\Contact\Edit\SaveButton</item>
    </item>

We will create our files: Create a GenericButton: The GenericButton is the element that allows other buttons to exist. This is the base that extends the other buttons.

app/code/Pfay/Contacts/Block/Adminhtml/Contact/Edit/GenericButton.php

<?php
namespace Pfay\Contacts\Block\Adminhtml\Contact\Edit;

use Magento\Search\Controller\RegistryConstants;

/**
 * Class GenericButton
 */
class GenericButton
{
    /**
     * Url Builder
     *
     * @var \Magento\Framework\UrlInterface
     */
    protected $urlBuilder;

    /**
     * Registry
     *
     * @var \Magento\Framework\Registry
     */
    protected $registry;

    /**
     * Constructor
     *
     * @param \Magento\Backend\Block\Widget\Context $context
     * @param \Magento\Framework\Registry $registry
     */
    public function __construct(
        \Magento\Backend\Block\Widget\Context $context,
        \Magento\Framework\Registry $registry
    ) {
        $this->urlBuilder = $context->getUrlBuilder();
        $this->registry = $registry;
    }

    /**
     * Return the synonyms group Id.
     *
     * @return int|null
     */
    public function getId()
    {
        $contact = $this->registry->registry('contact');
        return $contact ? $contact->getId() : null;
    }

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

Create a button to save our magento2 form Create the file

app/code/Pfay/Contacts/Block/Adminhtml/Contact/Edit/BackButton.php

In which you just configure the label of the button, the associated event and the form-role that automatically triggers events js for magento2.

<?php
namespace Pfay\Contacts\Block\Adminhtml\Contact\Edit;

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

/**
 * Class BackButton
 */
class BackButton extends GenericButton implements ButtonProviderInterface
{
    /**
     * @return array
     */
    public function getButtonData()
    {
        return [
            'label' => __('Back'),
            'on_click' => sprintf("location.href = '%s';", $this->getBackUrl()),
            'class' => 'back',
            'sort_order' => 10
        ];
    }

    /**
     * Get URL for back (reset) button
     *
     * @return string
     */
    public function getBackUrl()
    {
        return $this->getUrl('*/*/');
    }
}

Create a button to delete an object using our form Then create the file to delete an item from our formular

app/code/Pfay/Contacts/Block/Adminhtml/Contact/Edit/DeleteButton.php

Here it is more or less pariel but for the suppression:

<?php
namespace Pfay\Contacts\Block\Adminhtml\Contact\Edit;

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

/**
 * Class DeleteButton
 */
class DeleteButton extends GenericButton implements ButtonProviderInterface
{
    /**
     * @return array
     */
    public function getButtonData()
    {
        $data = [];
        if ($this->getId()) {
            $data = [
                'label' => __('Delete Contact'),
                'class' => 'delete',
                'on_click' => 'deleteConfirm(\''
                    . __('Are you sure you want to delete this contact ?')
                    . '\', \'' . $this->getDeleteUrl() . '\')',
                'sort_order' => 20,
            ];
        }
        return $data;
    }

    /**
     * @return string
     */
    public function getDeleteUrl()
    {
        return $this->getUrl('*/*/delete', ['pfay_contacts_id' => $this->getId()]);
    }
}

Create a reset button to reset our magento2 form

app/code/Pfay/Contacts/Block/Adminhtml/Contact/Edit/ResetButton.php

<?php
namespace Pfay\Contacts\Block\Adminhtml\Contact\Edit;

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

/**
 * Class ResetButton
 */
class ResetButton implements ButtonProviderInterface
{
    /**
     * @return array
     */
    public function getButtonData()
    {
        return [
            'label' => __('Reset'),
            'class' => 'reset',
            'on_click' => 'location.reload();',
            'sort_order' => 30
        ];
    }
}

Create a reset button to save our form

app/code/Pfay/Contacts/Block/Adminhtml/Contact/Edit/SaveButton.php

<?php
namespace Pfay\Contacts\Block\Adminhtml\Contact\Edit;

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

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

And here are !! Our buttons are created and theoretically, everything should work :) Create our delete action We create our delete action to remove an object from the Magento grid like this:

<?php
namespace Pfay\Contacts\Controller\Adminhtml\Test;
use Pfay\Contacts\Model\Contact as Contact;
use Magento\Backend\App\Action;

class Delete extends \Magento\Backend\App\Action
{
    public function execute()
    {
        $id = $this->getRequest()->getParam('id');

        if (!($contact = $this->_objectManager->create(Contact::class)->load($id))) {
            $this->messageManager->addError(__('Unable to proceed. Please, try again.'));
            $resultRedirect = $this->resultRedirectFactory->create();
            return $resultRedirect->setPath('*/*/index', array('_current' => true));
        }
        try{
            $contact->delete();
            $this->messageManager->addSuccess(__('Your contact has been deleted !'));
        } catch (Exception $e) {
            $this->messageManager->addError(__('Error while trying to delete contact: '));
            $resultRedirect = $this->resultRedirectFactory->create();
            return $resultRedirect->setPath('*/*/index', array('_current' => true));
        }

        $resultRedirect = $this->resultRedirectFactory->create();
        return $resultRedirect->setPath('*/*/index', array('_current' => true));
    }
}

Here is another tutorial for your reference. https://webkul.com/blog/create-ui-form-magento2-part-1/