0

Continuously appearing problem with the position element of the dynamic rows component if we wanna use drag&drop feature. For reference I use a Related Products rows grid at the Product edit form. In that js configuration a position field has visible = false property but nevertheless it is initiating properly via registry.async() in vendor/magento/module-ui/view/base/web/js/dynamic-rows/record.js file function.

I spent a lot of hours trying find out why is my position element is not initiating but with no results. Has anyone also faced with this annoying issue?


Here is an example of what I am trying to achieve:

Correct behavior

But in my case I've got this:

Incorrect behavior

0

After a lots of researching I finally found out a reason why it happens.

The main problem is a layout difference. In my case I have Tabs layout unlike the Product edit page where we have 1 column (generic) layout. For the Generic layout configuration processing Magento uses class \Magento\Framework\View\Layout\Generic and addChildren method which responsible for collecting all children components respectively.

But for the Tabs layout Magento uses an another class \Magento\Ui\Component\Layout\Tabs with redefined addChildren fucntion. We should look into one interesting method in that class - prepareChildComponents. It renders all children components and checking for their visibility:

$isVisible = $child->getData('config/visible');
if ($isVisible !== null && $isVisible == 0) {
    continue;
}

If the child component is invisible it's not rendering at all and not adding as a child to the component. That's why position field disappears from the html and Drag&Drop functionality didn't work properly.

I decided to rewrite this class and its method simultaneously. I created adminhtml/di.xml file with the next configuration:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Ui\Component\Layout\Tabs" type="MyNameSpace\MyModule\Component\Layout\Tabs" />

And created MyNameSpace\MyModule\Component\Layout\Tabs respectively where I added method to check for the dynamic rows record component:

namespace MyNameSpace\MyModule\Component\Layout;

use Magento\Framework\View\Element\UiComponentInterface;

class Tabs extends \Magento\Ui\Component\Layout\Tabs
{
    /**
     * @param $component
     * @return bool
     */
    protected function isDynamicRowsRecordComponent($component)
    {
        return $component->getConfig('component') == 'Magento_Ui/js/dynamic-rows/record';
    }

    /**
     * @param UiComponentInterface $component
     * @param string $parentName
     * @return array
     */
    protected function prepareChildComponents(UiComponentInterface $component, $parentName)
    {
        $name = $component->getName();
        $childComponents = $component->getChildComponents();

        $childrenStructure = [];
        foreach ($childComponents as $childName => $child) {
            $isVisible = $child->getData('config/visible');
            if ($isVisible !== null && $isVisible == 0 && !$this->isDynamicRowsRecordComponent($component)) {
                continue;
            }
            /**
             * @var UiComponentInterface $childComponent
             * @var array $childStructure
             */
            list($childComponent, $childStructure) = $this->prepareChildComponents($child, $component->getName());
            $childrenStructure = array_merge($childrenStructure, $childStructure);
            $component->addComponent($childName, $childComponent);
        }

        $structure = [
            $name => [
                'type' => $component->getComponentName(),
                'name' => $component->getName(),
                'children' => $childrenStructure
            ]
        ];

        list($config, $dataScope) = $this->prepareConfig((array) $component->getConfiguration(), $name, $parentName);

        if ($dataScope !== false) {
            $structure[$name]['dataScope'] = $dataScope;
        }
        $structure[$name]['config'] = $config;

        return [$component, $structure];
    }
}

Now it works as it should. Hope it helps anyone!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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