3

How can I load the data from customer DataProvider plugin into my ui_component dynamicRows?

I have created a new tab in the admin customer edit form, and added my ui_component, which seems to work well. But I can't populate the data already stored in my database.

I have tried to add xml for DataSource, but I think that has conflict with original customer_form.xml DataSource "customer_form.customer_form_data_source" because when I add DataSource, the page no longer loads.

dataSource XML:

<dataSource name="mycustomrows">
    <argument name="dataProvider" xsi:type="configurableObject">
        <argument name="class" xsi:type="string">MyVendor\MyModule\Model\Customer\DataProvider</argument>
        <argument name="primaryFieldName" xsi:type="string">id</argument>
        <argument name="requestFieldName" xsi:type="string">id</argument>
        <argument name="meta" xsi:type="array">
            <item name="mycustomrows" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="label" xsi:type="string" translate="true">My Custom Rows</item>
                </item>
            </item>
        </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>
    </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>

dataProvider for dataSource:

<?php

namespace MyVendor\MyModule\Model\Customer;

class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
{
   protected $loadedData;
   protected $collectionFactory;

   public function __construct(
       $name,
       $primaryFieldName,
       $requestFieldName,
       \MyVendor\MyModule\Model\ResourceModel\Row\Collection $collection,
       \MyVendor\MyModule\Model\ResourceModel\Row\CollectionFactory $collectionFactory,
       array $meta = [],
       array $data = []
   ) {
       $this->collection = $collection;
       $this->collectionFactory = $collectionFactory;

       parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data);
   }

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

       $collection = $this->collectionFactory->create(); 
       // add Filter for Customer ID
       //->setOrder('position', 'ASC');
       $items = $collection->getItems();

       foreach ($items as $item) {
           $this->loadedData[$item->getId()] = $item->getData();
       }

       return $this->loadedData;
   }
}

I believe the data has to be loaded with Plugin for "Magento\Customer\Model\Customer\DataProvider" as I am doing below, but I can't seem to get populate rows on load.

view/adminhtml/ui_component/customer_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">
    <fieldset name="mycustomrows">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="label" xsi:type="string" translate="true">My Custom Rows</item>
                <item name="sortOrder" xsi:type="number">10</item>
            </item>
        </argument>
        <dynamicRows name="mycustomrows">
            <settings>
                <addButtonLabel translate="true">Add Row</addButtonLabel>
                <additionalClasses>
                    <class name="admin__field-wide">true</class>
                </additionalClasses>
                <componentType>dynamicRows</componentType>
            </settings>

            <container name="record" component="Magento_Ui/js/dynamic-rows/record">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="isTemplate" xsi:type="boolean">true</item>
                        <item name="is_collection" xsi:type="boolean">true</item>
                        <item name="componentType" xsi:type="string">container</item>
                        <item name="positionProvider" xsi:type="string">position</item>
                    </item>
                </argument>


                <field name="mycustomrows_select1" formElement="select" sortOrder="10">
                    <settings>
                        <dataType>text</dataType>
                        <label translate="true">Select Field 1</label>
                        <disabled>false</disabled>
                        <dataScope>mycustomrows_select1</dataScope>
                    </settings>
                    <formElements>
                        <select>
                            <settings>
                                <options class="MyVendor\MyModule\Model\Source\SelectFieldOne"/>
                            </settings>
                        </select>
                    </formElements>
                </field>
                <field name="mycustomrows_input1" sortOrder="20" formElement="input">
                    <argument name="data" xsi:type="array">
                        <item name="config" xsi:type="array">
                            <item name="source" xsi:type="string">customer</item>
                        </item>
                    </argument>
                    <settings>
                        <label translate="true">Text Field 1</label>
                        <dataType>text</dataType>
                        <dataScope>mycustomrows_text1</dataScope>
                    </settings>
                </field>
                <actionDelete sortOrder="30">
                    <argument name="data" xsi:type="array">
                        <item name="config" xsi:type="array">
                            <item name="componentType" xsi:type="string">actionDelete</item>
                            <item name="dataType" xsi:type="string">text</item>
                            <item name="fit" xsi:type="boolean">false</item>
                            <item name="label" xsi:type="string">Actions</item>
                            <item name="sortOrder" xsi:type="string">500</item>
                            <item name="additionalClasses" xsi:type="string">data-grid-actions-cell</item>
                            <item name="template" xsi:type="string">Magento_Backend/dynamic-rows/cells/action-delete</item>
                        </item>
                    </argument>
                </actionDelete>
            </container>
        </dynamicRows>
    </fieldset>
</form>

etc/adminhtml/di.xml

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Customer\Model\Customer\DataProvider">
        <plugin name="customer_get_mycustomrows" type="MyVendor\MyModule\Model\Customer\DataProvider" sortOrder="5" />
    </type>
</config>

Model/Customer/DataProvider.php

<?php
namespace MyVendor\MyModule\Model\Customer;

class DataProvider 
{
    protected $collection;
    protected $collectionFactory;
    protected $loadedData;

    public function __construct(
        \MyVendor\MyModule\Model\ResourceModel\Row\Collection $collection,
        \MyVendor\MyModule\Model\ResourceModel\Row\CollectionFactory $collectionFactory,
        array $data = []
    ) {
        $this->collection = $collection;
        $this->collectionFactory = $collectionFactory;
    }

    public function afterGetData(\Magento\Customer\Model\Customer\DataProvider $subject, $result)
    {
        if($result){
            $customer_id = key($result);
            $customerData =  $result[$customer_id]['customer'];

            if(is_null($this->loadedData)) {
                $this->loadedData = array();
                $collection = $this->collectionFactory->create(); //->setOrder('position', 'ASC');
                $items = $collection->getItems();

                foreach ($items as $item) {
                    $this->loadedData[] = $item->getData();
                }
            }

            $result[$customer_id]['customer']["mycustomrows"] = $this->loadedData;
        }
        return $result;
    }

}

I can't seem to get any records populated when I load a customer edit page.

1
  • I am running into the same issue, were you able to find a solution? Commented May 8, 2019 at 23:52

2 Answers 2

2

You need to change in the last two steps,

Step-1, you need to add a plugin for DataProviderWithDefaultAddresses in place of DataProvider,

etc/adminhtml/di.xml

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Customer\Model\Customer\DataProviderWithDefaultAddresses">
        <plugin name="customer_get_mycustomrows" type="MyVendor\MyModule\Model\Customer\DataProvider" sortOrder="5" />
    </type>
</config>

And in below class use DataProviderWithDefaultAddresses as a subject in the argument, Model/Customer/DataProvider.php

<?php
namespace MyVendor\MyModule\Model\Customer;

class DataProvider 
{
    protected $collection;
    protected $collectionFactory;
    protected $loadedData;

    public function __construct(
        \MyVendor\MyModule\Model\ResourceModel\Row\Collection $collection,
        \MyVendor\MyModule\Model\ResourceModel\Row\CollectionFactory $collectionFactory,
        array $data = []
    ) {
        $this->collection = $collection;
        $this->collectionFactory = $collectionFactory;
    }

    public function afterGetData(\Magento\Customer\Model\Customer\DataProviderWithDefaultAddresses $subject, $result)
    {
        if($result){
            $customer_id = key($result);
            $customerData =  $result[$customer_id]['customer'];

            if(is_null($this->loadedData)) {
                $this->loadedData = array();
                $collection = $this->collectionFactory->create(); //->setOrder('position', 'ASC');
                $items = $collection->getItems();

                foreach ($items as $item) {
                    $this->loadedData[] = $item->getData();
                }
            }

            $result[$customer_id]['customer']["mycustomrows"] = $this->loadedData;
        }
        return $result;
    }

}

After run compile command and clear cache data will be loaded into edit form.

2

This will load custom collection in dynamic rows:

customer_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">
    <fieldset name="customdata">
       <argument name="data" xsi:type="array">
           <item name="config" xsi:type="array">
               <item name="label" xsi:type="string" translate="true">Custom data</item>
               <item name="sortOrder" xsi:type="number">1</item>
           </item>
       </argument>
       <container name="customdata">
           <argument name="data" xsi:type="array">
               <item name="config" xsi:type="array">
                    <item name="component" xsi:type="string">Magento_Ui/js/dynamic-rows/dynamic-rows</item>
                    <item name="template" xsi:type="string">ui/dynamic-rows/templates/default</item>
                    <item name="componentType" xsi:type="string">dynamicRows</item>
                    <item name="recordTemplate" xsi:type="string">record</item>
                    <item name="addButtonLabel" xsi:type="string">Add new</item>
                    <item name="deleteProperty" xsi:type="boolean">false</item>
                    <item name="additionalClasses" xsi:type="array">
                        <item name="admin__field-wide" xsi:type="boolean">true</item>
                    </item>
               </item>
           </argument>
           <container name="record">
               <argument name="data" xsi:type="array">
                   <item name="config" xsi:type="array">
                       <item name="label" xsi:type="string" translate="true">Custom data</item>
                       <item name="component" xsi:type="string" translate="true">Magento_Ui/js/dynamic-rows/record</item>
                       <item name="isTemplate" xsi:type="boolean">true</item>
                       <item name="is_collection" xsi:type="boolean">true</item>
                       <item name="showFallbackReset" xsi:type="boolean">false</item>
                   </item>
               </argument>
                <field formElement="input" name="field" sortOrder="90">
                    <argument name="data" xsi:type="array">
                        <item name="config" xsi:type="array">
                            <item name="source" xsi:type="string">Data</item>
                        </item>
                    </argument>
                    <settings>
                        <dataType>text</dataType>
                        <label translate="true">Field</label>
                        <dataScope>field</dataScope>
                        <validation>
                            <rule name="required-entry" xsi:type="boolean">true</rule>
                        </validation>
                    </settings>
                </field>
           </container>
       </container>
   </fieldset>
</form>

DataProvider.php

protected $collection;
protected $collectionFactory;

protected $loadedData;

public function __construct(
    \Vendor\Vendor\Model\ResourceModel\Vendor\Collection $collection,
    \Vendor\Vendor\Model\ResourceModel\Vendor\CollectionFactory $collectionFactory,
    array $data = []
) {
    $this->collection = $collection;
    $this->collectionFactory = $collectionFactory;  
}

public function afterGetData(\Magento\Customer\Model\Customer\DataProviderWithDefaultAddresses $subject, $result)
{
    if ($result)
    {
        $customer_id = key($result);
        $customerData =  $result[$customer_id]['customer'];

        if (is_null($this->loadedData)) 
        {
            $this->loadedData = [];

            $collection = $this->collectionFactory->create();

            $items = $collection->getItems();

            foreach ($items as $item) 
            {
                $result[$customer_id]["customdata"]["customdata"][] = $item->getData();
            }
        }
    }

    return $result;
}

di.xml

<type name="Magento\Customer\Model\Customer\DataProviderWithDefaultAddresses">
    <plugin name="customdata" type="Vendor\Vendor\Model\Customer\DataProvider" sortOrder="5" />
</type>
1
  • This would be a better answer if you explained the why and not just the what. Nothing in UI docs (I've read/found) suggests that a plugin is needed to populate the UI component data. Is this a specific case for adding components to core forms like customer and product? If so, there's no mention of this in the UI docs. Neither does the core code itself appear to load say related product data like this. According to the UI docs, declaring the dataProvider and dataSource should be enough to populate UI components. Commented Mar 31, 2022 at 9:23

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.