As we completed the admin grid part now we move to part Magento 2 create basic module admin form. In this tutorial include admin new ui component form , admin edit ui component form , form data provider,edit form delete button and add different button to form. Now move on creating the ui component form.
Add New Form controller
Now we create controller for adding the new record. This controller just forwarding to edit controller. Create controller for NewAction.php in following directory
QaisarSatti\HelloWorld\Controller\Adminhtml\Index\
/**
* Hello World
*
* @category QaisarSatti
* @package QaisarSatti_HelloWorld
* @author Muhammad Qaisar Satti
* @Email qaisarssatti@gmail.com
*
*/
namespace QaisarSatti\HelloWorld\Controller\Adminhtml\Index;
class NewAction extends \Magento\Backend\App\Action
{
/**
* @var \Magento\Backend\Model\View\Result\Forward
*/
protected $resultForwardFactory;
/**
* @param \Magento\Backend\App\Action\Context $context
* @param \Magento\Backend\Model\View\Result\ForwardFactory $resultForwardFactory
*/
public function __construct(
\Magento\Backend\App\Action\Context $context,
\Magento\Backend\Model\View\Result\ForwardFactory $resultForwardFactory
) {
$this->resultForwardFactory = $resultForwardFactory;
parent::__construct($context);
}
/**
* {@inheritdoc}
*/
protected function _isAllowed()
{
return $this->_authorization->isAllowed('QaisarSatti_HelloWorld::helloworld1');
}
/**
* Forward to edit
*
* @return \Magento\Backend\Model\View\Result\Forward
*/
public function execute()
{
/** @var \Magento\Backend\Model\View\Result\Forward $resultForward */
$resultForward = $this->resultForwardFactory->create();
return $resultForward->forward('edit');
}
}
Edit Form
Edit form is based on three parts edit controller, edit layout, and edit ui component. So we go through one by one.
Edit Form controller
Now we create controller for adding the new record. This controller just forwarding to edit controller. Create controller for Edit.php in following directory
QaisarSatti\HelloWorld\Controller\Adminhtml\Index\
/**
* Hello World
*
* @category QaisarSatti
* @package QaisarSatti_HelloWorld
* @author Muhammad Qaisar Satti
* @Email qaisarssatti@gmail.com
*
*/
namespace QaisarSatti\HelloWorld\Controller\Adminhtml\Index;
class Edit extends \Magento\Backend\App\Action
{
/**
* @var \Magento\Framework\View\Result\PageFactory
*/
protected $resultPageFactory;
/**
* @param \Magento\Backend\App\Action\Context $context
* @param \Magento\Framework\Registry $coreRegistry
* @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
*/
public function __construct(
\Magento\Backend\App\Action\Context $context,
\Magento\Framework\Registry $coreRegistry,
\Magento\Framework\View\Result\PageFactory $resultPageFactory
) {
$this->resultPageFactory = $resultPageFactory;
parent::__construct($context, $coreRegistry);
}
/**
* Index action
*
* @return \Magento\Framework\Controller\ResultInterface
*/
public function execute()
{
$resultPage = $this->resultPageFactory->create();
$this->initPage($resultPage)->getConfig()->getTitle()->prepend(__('Manage Post'));
return $resultPage;
}
protected function initPage($resultPage)
{
$resultPage->setActiveMenu('QaisarSatti_HelloWorld::helloworld1')
->addBreadcrumb(__('Manage Post'), __('Manage Post'))
->addBreadcrumb(__('Manage Post'), __('Manage Post'));
return $resultPage;
}
/**
* Check the permission to run it
*
* @return boolean
*/
protected function _isAllowed()
{
return $this->_authorization->isAllowed('QaisarSatti_HelloWorld::helloworld1');
}
}
Edit Form layout
Now we create layout file for edit. This helloworld_index_edit.xml file combine the ui component with edit controller. Create controller for helloworld_index_edit.xml in following directory
QaisarSatti\HelloWorld\view\adminhtml\layout\
<!--
/**
* Hello World
*
* @category QaisarSatti
* @package QaisarSatti_HelloWorld
* @author Muhammad Qaisar Satti
* @Email qaisarssatti@gmail.com
*
*/
-->
<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="helloworld_edit"/>
</referenceContainer>
</body>
</page>
Data Provider for Edit Form
Now create the data provider for admin form. Create DataProvider.php in following directory
QaisarSatti\HelloWorld\Model\HelloWorld\
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace QaisarSatti\HelloWorld\Model\HelloWorld;
use QaisarSatti\HelloWorld\Model\ResourceModel\HelloWorld\CollectionFactory;
use Magento\Framework\App\Request\DataPersistorInterface;
/**
* Class DataProvider
*/
class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
{
/**
* @var \Magento\Cms\Model\ResourceModel\Block\Collection
*/
protected $collection;
/**
* @var DataPersistorInterface
*/
protected $dataPersistor;
/**
* @var array
*/
protected $loadedData;
/**
* Constructor
*
* @param string $name
* @param string $primaryFieldName
* @param string $requestFieldName
* @param CollectionFactory $blockCollectionFactory
* @param DataPersistorInterface $dataPersistor
* @param array $meta
* @param array $data
*/
public function __construct(
$name,
$primaryFieldName,
$requestFieldName,
CollectionFactory $helloworldCollectionFactory,
DataPersistorInterface $dataPersistor,
array $meta = [],
array $data = []
) {
$this->collection = $helloworldCollectionFactory->create();
$this->dataPersistor = $dataPersistor;
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();
/** @var \Magento\Cms\Model\Block $block */
foreach ($items as $block) {
$this->loadedData[$block->getId()] = $block->getData();
}
$data = $this->dataPersistor->get('helloworld');
if (!empty($data)) {
$block = $this->collection->getNewEmptyItem();
$block->setData($data);
$this->loadedData[$block->getId()] = $block->getData();
$this->dataPersistor->clear('helloworld');
}
return $this->loadedData;
}
}
Edit Form Generic Button
Create GenericButton.php in following directory
QaisarSatti\HelloWorld\Block\Adminhtml\HelloWorld\Edit\
/**
* Hello World
*
* @category QaisarSatti
* @package QaisarSatti_HelloWorld
* @author Muhammad Qaisar Satti
* @Email qaisarssatti@gmail.com
*
*/
namespace QaisarSatti\HelloWorld\Block\Adminhtml\HelloWorld\Edit;
use Magento\Backend\Block\Widget\Context;
use Magento\Framework\Exception\NoSuchEntityException;
/**
* Class GenericButton
*/
class GenericButton
{
/**
* @var Context
*/
protected $context;
/**
* @var BlockRepositoryInterface
*/
/**
* @param Context $context
*/
public function __construct(
Context $context
) {
$this->context = $context;
}
/**
* Return Post ID
*
* @return int|null
*/
public function getBlockId()
{
try {
return $this->context->getRequest()->getParam('post_id');
} catch (NoSuchEntityException $e) {
}
return null;
}
/**
* 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);
}
}
Edit Form Back Button
Create BackButton.php in following directory
QaisarSatti\HelloWorld\Block\Adminhtml\HelloWorld\Edit\
/**
* Hello World
*
* @category QaisarSatti
* @package QaisarSatti_HelloWorld
* @author Muhammad Qaisar Satti
* @Email qaisarssatti@gmail.com
*
*/
namespace QaisarSatti\HelloWorld\Block\Adminhtml\HelloWorld\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('*/*/');
}
}
Edit Form Delete Button
Create DeleteButton.php in following directory
QaisarSatti\HelloWorld\Block\Adminhtml\HelloWorld\Edit\
/**
* Hello World
*
* @category QaisarSatti
* @package QaisarSatti_HelloWorld
* @author Muhammad Qaisar Satti
* @Email qaisarssatti@gmail.com
*
*/
namespace QaisarSatti\HelloWorld\Block\Adminhtml\HelloWorld\Edit;
use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface;
/**
* Class DeleteButton
*/
class DeleteButton extends GenericButton implements ButtonProviderInterface
{
/**
* @return array
*/
public function getButtonData()
{
$data = [];
return $data;
if ($this->getId()) {
$data = [
'label' => __('Delete Block'),
'class' => 'delete',
'on_click' => 'deleteConfirm(\'' . __(
'Are you sure you want to do this?'
) . '\', \'' . $this->getDeleteUrl() . '\')',
'sort_order' => 20,
];
}
return $data;
}
/**
* @return string
*/
public function getDeleteUrl()
{
return $this->getUrl('*/*/delete', ['id' => $this->getId()]);
}
}
Edit Form Reset Button
Create ResetButton.php in following directory
QaisarSatti\HelloWorld\Block\Adminhtml\HelloWorld\Edit\
/**
* Hello World
*
* @category QaisarSatti
* @package QaisarSatti_HelloWorld
* @author Muhammad Qaisar Satti
* @Email qaisarssatti@gmail.com
*
*/
namespace QaisarSatti\HelloWorld\Block\Adminhtml\HelloWorld\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
];
}
}
Edit Form SaveAndContinue Button
Create SaveAndContinueButton.php in following directory
QaisarSatti\HelloWorld\Block\Adminhtml\HelloWorld\Edit\
/**
* Hello World
*
* @category QaisarSatti
* @package QaisarSatti_HelloWorld
* @author Muhammad Qaisar Satti
* @Email qaisarssatti@gmail.com
*
*/
namespace QaisarSatti\HelloWorld\Block\Adminhtml\HelloWorld\Edit;
use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface;
/**
* Class SaveAndContinueButton
*/
class SaveAndContinueButton extends GenericButton implements ButtonProviderInterface
{
/**
* @return array
*/
public function getButtonData()
{
return [
'label' => __('Save and Continue Edit'),
'class' => 'save',
'data_attribute' => [
'mage-init' => [
'button' => ['event' => 'saveAndContinueEdit'],
],
],
'sort_order' => 80,
];
}
}
Edit Form Save Button
Create SaveButton.php in following directory
QaisarSatti\HelloWorld\Block\Adminhtml\HelloWorld\Edit\
/**
* Hello World
*
* @category QaisarSatti
* @package QaisarSatti_HelloWorld
* @author Muhammad Qaisar Satti
* @Email qaisarssatti@gmail.com
*
*/
namespace QaisarSatti\HelloWorld\Block\Adminhtml\HelloWorld\Edit;
use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface;
/**
* Class SaveButton
* @package Magento\Customer\Block\Adminhtml\Edit
*/
class SaveButton extends GenericButton implements ButtonProviderInterface
{
/**
* @return array
*/
public function getButtonData()
{
return [
'label' => __('Save Post'),
'class' => 'save primary',
'data_attribute' => [
'mage-init' => ['button' => ['event' => 'save']],
'form-role' => 'save',
],
'sort_order' => 90,
];
}
}
Edit Form UI Component
Now create the ui component for the grid. You can read detail of edit form from tutorial Magento 2 create custom ui component admin form. Now we Create helloworld_edit.xml in following directory
QaisarSatti\HelloWorld\view\adminhtml\ui_component\
<!--
/**
* Hello World
*
* @category QaisarSatti
* @package QaisarSatti_HelloWorld
* @author Muhammad Qaisar Satti
* @Email qaisarssatti@gmail.com
*
*/
-->
<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">helloworld_edit.helloworld_data_source</item>
<item name="deps" xsi:type="string">helloworld_edit.helloworld_data_source</item>
</item>
<item name="label" xsi:type="string" translate="true">Manage Post</item>
<item name="config" xsi:type="array">
<item name="dataScope" xsi:type="string">data</item>
<item name="namespace" xsi:type="string">helloworld_edit</item>
</item>
<item name="template" xsi:type="string">templates/form/collapsible</item>
<item name="buttons" xsi:type="array">
<item name="back" xsi:type="string">QaisarSatti\HelloWorld\Block\Adminhtml\HelloWorld\Edit\BackButton</item>
<item name="delete" xsi:type="string">QaisarSatti\HelloWorld\Block\Adminhtml\HelloWorld\Edit\DeleteButton</item>
<item name="reset" xsi:type="string">QaisarSatti\HelloWorld\Block\Adminhtml\HelloWorld\Edit\ResetButton</item>
<item name="save" xsi:type="string">QaisarSatti\HelloWorld\Block\Adminhtml\HelloWorld\Edit\SaveButton</item>
<item name="save_and_continue" xsi:type="string">QaisarSatti\HelloWorld\Block\Adminhtml\HelloWorld\Edit\SaveAndContinueButton</item>
</item>
</argument>
<dataSource name="helloworld_data_source">
<argument name="dataProvider" xsi:type="configurableObject">
<argument name="class" xsi:type="string">QaisarSatti\HelloWorld\Model\HelloWorld\DataProvider</argument>
<argument name="name" xsi:type="string">helloworld_data_source</argument>
<argument name="primaryFieldName" xsi:type="string">post_id</argument>
<argument name="requestFieldName" xsi:type="string">id</argument>
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="submit_url" xsi:type="url" path="helloworld/index/save"/>
</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/form/provider</item>
</item>
</argument>
</dataSource>
<fieldset name="general">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="label" xsi:type="string"/>
</item>
</argument>
<field name="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">helloworld</item>
</item>
</argument>
</field>
<field name="title">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="label" xsi:type="string">Title:</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">helloworld</item>
<item name="validation" xsi:type="array">
<item name="required-entry" xsi:type="boolean">true</item>
</item>
</item>
</argument>
</field>
<field name="content">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="label" xsi:type="string">Content:</item>
<item name="visible" xsi:type="boolean">true</item>
<item name="dataType" xsi:type="string">textarea</item>
<item name="formElement" xsi:type="string">textarea</item>
<item name="source" xsi:type="string">helloworld</item>
</item>
</argument>
</field>
</fieldset>
</form>
Save Form Data
Save controller have two parts. First is check PostDataProcessor, and second is save controller.
Post Data Processor
This is for validation purposes of form. Create PostDataProcessor.php in following directory
QaisarSatti\HelloWorld\Controller\Adminhtml\Index\
/**
* Hello World
*
* @category QaisarSatti
* @package QaisarSatti_HelloWorld
* @author Muhammad Qaisar Satti
* @Email qaisarssatti@gmail.com
*
*/
namespace QaisarSatti\HelloWorld\Controller\Adminhtml\Index;
class PostDataProcessor
{
/**
* @var \Magento\Framework\Stdlib\DateTime\Filter\Date
*/
protected $dateFilter;
/**
* @var \Magento\Framework\View\Model\Layout\Update\ValidatorFactory
*/
protected $validatorFactory;
/**
* @var \Magento\Framework\Message\ManagerInterface
*/
protected $messageManager;
/**
* @param \Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter
* @param \Magento\Framework\Message\ManagerInterface $messageManager
* @param \Magento\Framework\View\Model\Layout\Update\ValidatorFactory $validatorFactory
*/
public function __construct(
\Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter,
\Magento\Framework\Message\ManagerInterface $messageManager,
\Magento\Framework\View\Model\Layout\Update\ValidatorFactory $validatorFactory
) {
$this->dateFilter = $dateFilter;
$this->messageManager = $messageManager;
$this->validatorFactory = $validatorFactory;
}
/**
* Filtering posted data. Converting localized data if needed
*
* @param array $data
* @return array
*/
public function filter($data)
{
$filterRules = [];
foreach (['custom_theme_from', 'custom_theme_to'] as $dateField) {
if (!empty($data[$dateField])) {
$filterRules[$dateField] = $this->dateFilter;
}
}
return (new \Zend_Filter_Input($filterRules, [], $data))->getUnescaped();
}
/**
* Validate post data
*
* @param array $data
* @return bool Return FALSE if someone item is invalid
*/
public function validate($data)
{
$errorNo = true;
if (!empty($data['layout_update_xml']) || !empty($data['custom_layout_update_xml'])) {
/** @var $validatorCustomLayout \Magento\Framework\View\Model\Layout\Update\Validator */
$validatorCustomLayout = $this->validatorFactory->create();
if (!empty($data['layout_update_xml']) && !$validatorCustomLayout->isValid($data['layout_update_xml'])) {
$errorNo = false;
}
if (!empty($data['custom_layout_update_xml'])
&& !$validatorCustomLayout->isValid($data['custom_layout_update_xml'])
) {
$errorNo = false;
}
foreach ($validatorCustomLayout->getMessages() as $message) {
$this->messageManager->addError($message);
}
}
return $errorNo;
}
/**
* Check if required fields is not empty
*
* @param array $data
* @return bool
*/
public function validateRequireEntry(array $data)
{
$requiredFields = [
'title' => __('Title')
];
$errorNo = true;
foreach ($data as $field => $value) {
if (in_array($field, array_keys($requiredFields)) && $value == '') {
$errorNo = false;
$this->messageManager->addError(
__('To apply changes you should fill in hidden required "%1" field', $requiredFields[$field])
);
}
}
return $errorNo;
}
}
Form Save Data Controller
Now we save the data to our table.Create Save.php in following directory
QaisarSatti\HelloWorld\Controller\Adminhtml\Index\
/**
* Hello World
*
* @category QaisarSatti
* @package QaisarSatti_HelloWorld
* @author Muhammad Qaisar Satti
* @Email qaisarssatti@gmail.com
*
*/
namespace QaisarSatti\HelloWorld\Controller\Adminhtml\Index;
use Magento\Backend\App\Action;
use QaisarSatti\HelloWorld\Model\HelloWorld;
use Magento\Framework\App\Request\DataPersistorInterface;
use Magento\Framework\Exception\LocalizedException;
class Save extends \Magento\Backend\App\Action
{
const ADMIN_RESOURCE = 'QaisarSatti_HelloWorld::helloworld1';
protected $dataProcessor;
protected $dataPersistor;
protected $model;
public function __construct(
Action\Context $context,
PostDataProcessor $dataProcessor,
HelloWorld $model,
DataPersistorInterface $dataPersistor
) {
$this->dataProcessor = $dataProcessor;
$this->dataPersistor = $dataPersistor;
$this->model = $model;
parent::__construct($context);
}
public function execute()
{
$data = $this->getRequest()->getPostValue();
$resultRedirect = $this->resultRedirectFactory->create();
if ($data) {
$data = $this->dataProcessor->filter($data);
$id = $this->getRequest()->getParam('id');
if ($id) {
$this->model->load($id);
}
$this->model->setData($data);
$this->_eventManager->dispatch(
'helloworld_prepare_save',
['helloworld' => $this->model, 'request' => $this->getRequest()]
);
if (!$this->dataProcessor->validate($data)) {
return $resultRedirect->setPath('*/*/edit', ['id' => $this->model->getId(), '_current' => true]);
}
try {
$this->model->save();
$this->messageManager->addSuccess(__('You saved the Post.'));
$this->dataPersistor->clear('helloworld');
if ($this->getRequest()->getParam('back')) {
return $resultRedirect->setPath(
'*/*/edit',
['id' => $this->model->getId(),
'_current' => true]
);
}
return $resultRedirect->setPath('*/*/');
} catch (LocalizedException $e) {
$this->messageManager->addError($e->getMessage());
} catch (\Exception $e) {
$this->messageManager->addException($e, __('Something went wrong while saving the Post.'));
}
$this->dataPersistor->set('helloworld', $data);
return $resultRedirect->setPath('*/*/edit', ['id' => $this->getRequest()->getParam('id')]);
}
return $resultRedirect->setPath('*/*/');
}
}
Form Delete Button Controller
Create Delete.php in following directory
QaisarSatti\HelloWorld\Controller\Adminhtml\Index\
/**
* Hello World
*
* @category QaisarSatti
* @package QaisarSatti_HelloWorld
* @author Muhammad Qaisar Satti
* @Email qaisarssatti@gmail.com
*
*/
namespace QaisarSatti\HelloWorld\Controller\Adminhtml\Index;
use Magento\Backend\App\Action;
class Delete extends \Magento\Backend\App\Action
{
const ADMIN_RESOURCE = 'QaisarSatti_HelloWorld::helloworld1';
protected $model;
public function __construct(
Action\Context $context,
\QaisarSatti\HelloWorld\Model\HelloWorld $model
) {
$this->model = $model;
parent::__construct($context);
}
public function execute()
{
// check if we know what should be deleted
$id = $this->getRequest()->getParam('id');
/** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
$resultRedirect = $this->resultRedirectFactory->create();
if ($id) {
$title = "";
try {
$this->model->load($id);
$title = $this->model->getTitle();
$this->model->delete();
// display success message
$this->messageManager->addSuccess(__('The post has been deleted.'));
// go to grid
$this->_eventManager->dispatch(
'adminhtml_helloworld_on_delete',
['title' => $title, 'status' => 'success']
);
return $resultRedirect->setPath('*/*/');
} catch (\Exception $e) {
$this->_eventManager->dispatch(
'adminhtml_helloworld_on_delete',
['title' => $title, 'status' => 'fail']
);
// display error message
$this->messageManager->addError($e->getMessage());
// go back to edit form
return $resultRedirect->setPath('*/*/edit', ['id' => $id]);
}
}
// display error message
$this->messageManager->addError(__('We can\'t find a post to delete.'));
// go to grid
return $resultRedirect->setPath('*/*/');
}
}
Now we complete the custom admin form. Now move to fourth part Magento 2 create basic module frontend part 4.