8

Im trying to build a custom admin form (using ui components) for a custom entity. We can assume the entity is very simple(e.g. id,name)

One thing that i have hard time with, is populating the form with data.

For this purpose i wrote a custom data provider which looks something like this:

public function getData()
{
 if (isset($this->loadedData)) {
 return $this->loadedData;
 }
 $items = $this->collection->getItems();
 /** @var Customer $customer */
 foreach ($items as $faq) {
 $this->loadedData[$faq->getId()] = $faq->getData();
 }
 $data = $this->getSession()->getFormData();
 if (!empty($data)) {
 $faqId = isset($data) ? $data : null;
 $this->loadedData[$faqId] = $data;
 $this->getSession()->unsFormData();
 }
 return $this->loadedData;
}

So the actual data are right under the id of the entity.

The ui component has a single fieldset with one field:

<fieldset name="general">
 <argument name="data" xsi:type="array">
 <item name="config" xsi:type="array">
 <item name="label" xsi:type="string" translate="true">Conditions</item>
 </item>
 </argument>
 <field name="name">
 <argument name="data" xsi:type="array">
 <item name="config" xsi:type="array">
 <item name="dataType" xsi:type="string">text</item>
 <item name="label" xsi:type="string" translate="true">Label</item>
 <item name="formElement" xsi:type="string">input</item>
 <item name="dataScope" xsi:type="string">name</item>
 <item name="source" xsi:type="string">general</item>
 <item name="validation" xsi:type="array">
 <item name="required-entry" xsi:type="boolean">true</item>
 </item>
 </item>
 </argument>
 </field>
</fieldset>

The problem is, that the field never gets populated. Only way at the moment is to change stracture of the array returned by data provider:

$this->loadedData[$faq->getId()]['general'] = $faq->getData();

So the structure of the array has the same structure as fieldset -> field in the xml.

This seems to make some sense, however when i look how CMS module is defined for pages and blocks, it doesn't use the fieldset -> field hierarchy.

The data providers don't contain the fieldset key anywhere(or at least not from the getData) method, but the xml uses magical source 'block'.

For example for block

\Magento\Cms\Model\Block\DataProvider
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('cms_block');
 if (!empty($data)) {
 $block = $this->collection->getNewEmptyItem();
 $block->setData($data);
 $this->loadedData[$block->getId()] = $block->getData();
 $this->dataPersistor->clear('cms_block');
 }
 return $this->loadedData;
}
\Magento\Cms\view\ui_component\cms_block_form.xml
<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="is_active">
 <argument name="data" xsi:type="array">
 <item name="config" xsi:type="array">
 <item name="dataType" xsi:type="string">boolean</item>
 <item name="label" xsi:type="string" translate="true">Enable Block</item>
 <item name="formElement" xsi:type="string">checkbox</item>
 <item name="source" xsi:type="string">block</item>
 <item name="sortOrder" xsi:type="number">10</item>
 <item name="dataScope" xsi:type="string">is_active</item>
 <item name="prefer" xsi:type="string">toggle</item>
 <item name="valueMap" xsi:type="array">
 <item name="true" xsi:type="number">1</item>
 <item name="false" xsi:type="number">0</item>
 </item>
 <item name="default" xsi:type="number">1</item>
 </item>
 </argument>
 </field>

Where/How is this 'block' source created?

Do i really need to have the fieldset keys in data returned from the data provider?

Any help would be greatly appreciated.

asked Aug 23, 2016 at 19:01

2 Answers 2

1

Using dataPersistor to get Form data, thought you're using getSession

$data = $this->getSession()->getFormData();

Save action

<?php
namespace Vendor\Module\Controller\Adminhtml\Scheduler;
use Magento\Framework\Exception\LocalizedException;
class Save extends \Magento\Backend\App\Action
{
 protected $dataPersistor;
 /**
 * @param \Magento\Backend\App\Action\Context $context
 * @param \Magento\Framework\App\Request\DataPersistorInterface $dataPersistor
 */
 public function __construct(
 \Magento\Backend\App\Action\Context $context,
 \Magento\Framework\App\Request\DataPersistorInterface $dataPersistor
 ) {
 $this->dataPersistor = $dataPersistor;
 parent::__construct($context);
 }
 /**
 * Save actionSave action
 *
 * @return \Magento\Framework\Controller\ResultInterface
 */
 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('scheduler_id');
 $model = $this->_objectManager->create('Vendor\Module\Model\Scheduler')->load($id);
 if (!$model->getId() && $id) {
 $this->messageManager->addErrorMessage(__('This Scheduler no longer exists.'));
 return $resultRedirect->setPath('*/*/');
 }
 $model->setData($data);
 try {
 $model->save();
 $this->messageManager->addSuccessMessage(__('You saved the Scheduler.'));
 $this->dataPersistor->clear('engraving_scheduler');
 if ($this->getRequest()->getParam('back')) {
 return $resultRedirect->setPath('*/*/edit', ['scheduler_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 Scheduler.'));
 }
 $this->dataPersistor->set('engraving_scheduler', $data);
 return $resultRedirect->setPath('*/*/edit', ['scheduler_id' => $this->getRequest()->getParam('scheduler_id')]);
 }
 return $resultRedirect->setPath('*/*/');
 }
}

DataProvider

<?php
namespace Vendor\Module\Model\Scheduler;
use Vendor\Module\Model\ResourceModel\Scheduler\CollectionFactory;
use Magento\Framework\App\Request\DataPersistorInterface;
class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
{
 protected $dataPersistor;
 protected $loadedData;
 protected $collection;
 /**
 * Constructor
 *
 * @param string $name
 * @param string $primaryFieldName
 * @param string $requestFieldName
 * @param CollectionFactory $collectionFactory
 * @param DataPersistorInterface $dataPersistor
 * @param array $meta
 * @param array $data
 */
 public function __construct(
 $name,
 $primaryFieldName,
 $requestFieldName,
 CollectionFactory $collectionFactory,
 DataPersistorInterface $dataPersistor,
 array $meta = [],
 array $data = []
 ) {
 $this->collection = $collectionFactory->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();
 foreach ($items as $model) {
 $this->loadedData[$model->getId()] = $model->getData();
 }
 $data = $this->dataPersistor->get('engraving_scheduler');
 if (!empty($data)) {
 $model = $this->collection->getNewEmptyItem();
 $model->setData($data);
 $this->loadedData[$model->getId()] = $model->getData();
 $this->dataPersistor->clear('engraving_scheduler');
 }
 return $this->loadedData;
 }
}

ui 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">engraving_scheduler_form.scheduler_form_data_source</item>
 <item name="deps" xsi:type="string">engraving_scheduler_form.scheduler_form_data_source</item>
 </item>
 <item name="label" translate="true" xsi:type="string">General Information</item>
 <item name="config" xsi:type="array">
 <item name="dataScope" xsi:type="string">data</item>
 <item name="namespace" xsi:type="string">engraving_scheduler_form</item>
 </item>
 <item name="template" xsi:type="string">templates/form/collapsible</item>
 <item name="buttons" xsi:type="array">
 <item name="back" xsi:type="string">Vendor\Module\Block\Adminhtml\Scheduler\Edit\BackButton</item>
 <item name="delete" xsi:type="string">Vendor\Module\Block\Adminhtml\Scheduler\Edit\DeleteButton</item>
 <item name="save" xsi:type="string">Vendor\Module\Block\Adminhtml\Scheduler\Edit\SaveButton</item>
 <item name="save_and_continue" xsi:type="string">Vendor\Module\Block\Adminhtml\Scheduler\Edit\SaveAndContinueButton</item>
 </item>
 </argument>
 <dataSource name="scheduler_form_data_source">
 <argument name="dataProvider" xsi:type="configurableObject">
 <argument name="class" xsi:type="string">Vendor\Module\Model\Scheduler\DataProvider</argument>
 <argument name="name" xsi:type="string">scheduler_form_data_source</argument>
 <argument name="primaryFieldName" xsi:type="string">scheduler_id</argument>
 <argument name="requestFieldName" xsi:type="string">scheduler_id</argument>
 <argument name="data" xsi:type="array">
 <item name="config" xsi:type="array">
 <item name="submit_url" path="*/*/save" xsi:type="url"/>
 </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="label">
 <argument name="data" xsi:type="array">
 <item name="config" xsi:type="array">
 <item name="dataType" xsi:type="string">text</item>
 <item name="label" translate="true" xsi:type="string">Title</item>
 <item name="formElement" xsi:type="string">input</item>
 <item name="source" xsi:type="string">Scheduler</item>
 <item name="sortOrder" xsi:type="number">10</item>
 <item name="dataScope" xsi:type="string">label</item>
 <item name="validation" xsi:type="array">
 <item name="required-entry" xsi:type="boolean">true</item>
 </item>
 </item>
 </argument>
 </field>
 </fieldset>
</form>
Vivek Kumar
5,7932 gold badges26 silver badges55 bronze badges
answered Nov 15, 2018 at 4:23
2
  • Yes DataPersistor is a better way of doing this (the question is quite dated), but following up with ObjectManager use is not so good. Commented Nov 15, 2018 at 8:04
  • this answer gives the clarity for populating the data in UI form. Commented Dec 10, 2020 at 7:08
0

If you see the the customer edit form and get a look over the array returned by getdata() method . It sends out a array as [id][fieldset_name][data]. So here the key is mentioned during edit action.I guess this is the standard way of loading a UI form with data during edit.

answered Aug 24, 2016 at 5:13
4
  • Yes some of the forms use this and in case of tabbed form like customer it makes sense. However for very simple form this is way too complicated. The question I really have is, how the cms module doest this? Because the fieldset name is not used there. Commented Aug 24, 2016 at 5:51
  • @Langley did you find out much more about this? In the same predicament now. Thanks Commented Mar 9, 2017 at 12:49
  • Not that much, but ended up making it work somehow. Cant remember. Looking into the original question i think it may be wrong dataScope in the form configuration (not the fields) Commented Mar 9, 2017 at 16:55
  • Each form does contain a fieldset so format of [id][fieldset_name][data] if definitely correct. Commented Jun 25, 2018 at 8:03

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.