13

How can i send a id from my form to a insert Listing grid?

What i want to do, is in my form i load a grid with insert Listing.

In this grid i want all results with id of the form.

<insertListing name="insertlisting_colors_one">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="autoRender" xsi:type="boolean">true</item>
                <item name="imports" xsi:type="array">
                    <item name="spd_id" xsi:type="string">${ $.provider }:data.spd_id</item>
                </item>
                <item name="ns" xsi:type="string">colors_one_grid</item>
            </item>
        </argument>
    </insertListing>

Below is the code in the grid

<item name="filter_url_params" xsi:type="array">
                    <item name="color_amount" xsi:type="string">1</item>

                    <item name="spd_id" xsi:type="string">${ $.parentName }.spd_id</item>
                </item>
1
  • 2
    Do you get any solution for this... or anybody else.. I am also facing same issue... anyone can help?
    – Ashish Raj
    Sep 27, 2018 at 4:00

3 Answers 3

6

You need to set a value for the parameter render_url on the insertListing and then update this URL inside of your Data Provider. It is necessary to perform this action twice since you will need to have one Data Provider for your form component and another one specific for the listing component.

1 - Correct declaration of the insertListing component: (Vendor/Module/view/adminhtml/ui_component/vendor_module_form.xml)

<insertListing name="testInsertListing">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="dataLinks" xsi:type="array">
                    <item name="imports" xsi:type="boolean">false</item>
                    <item name="exports" xsi:type="boolean">true</item>
                </item>
                <item name="autoRender" xsi:type="boolean">true</item>
                <!-- the namespace attribute should be the name of the listing XML file -->
                <item name="ns" xsi:type="string">vendor_module_listing</item>
                <!-- This is the default render_url. We are going to update this value
                    in the DataProvider -->
                <item name="render_url" xsi:type="url" path="mui/index/render"/>
                <!-- Here we add the parameters that we want to add to the render_url. -->
                <item name="filter_url_params" xsi:type="array">
                    <!-- You can add as many as you want -->
                    <item name="id" xsi:type="string">*</item>
                </item>
                <item name="storageConfig" xsi:type="array">
                    <item name="indexField" xsi:type="string">id</item>
                </item>
            </item>
        </argument>
    </insertListing>

2 - Add the following changes to the Data Provider of the Form page. This will change the render_url by adding the parameter "id" to the end of the URL:

(Vendor/Module/Ui/DataProvider/[path-to-your-data-provider.php])

  • Add the RequestInterface class:
  • Declare the attribute $request on your Data Provider class.
  • Add a RequestInterface object to the __construct method; call the prepareUpdateUrl() method.
  • Add the prepareUpdateUrl() to your class:

Note: do not copy/paste the entire block below on your Data Provider. Instead, cherrypick the pieces that are missing from your code

<?php use Magento\Framework\App\RequestInterface;
use Magento\Framework\UrlInterface;

class MyListingDataProvider extends AbstractDataProvider
{
    protected $data;
    protected $meta;
    protected $collection;
    protected $urlBuilder;

    public function __construct(
        string $name,
        string $primaryFieldName,
        string $requestFieldName,
        Collection $collection,
        RequestInterface $request,
        UrlInterface $urlBuilder,
        array $meta = [],
        array $data = []
    )
    {
        $this->collection = $collection;
        $this->data = $data;
        $this->meta = $meta;
        $this->request = $request;
        $this->urlBuilder = $urlBuilder;

        $this->prepareUpdateUrl();

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

    protected function prepareUpdateUrl()
    {
        $id = $this->request->getParam('id');

        $this->meta = array_replace_recursive(
            $this->meta,
            [
                'testInsertListing' =>
                    ['arguments' => [
                        'data' => [
                            'config' => [
                                'render_url' => $this->urlBuilder
                                    ->getUrl('mui/index/render/id/' . $id),
                                'update_url' => $this->urlBuilder->getUrl('mui/index/render/id/' . $id)
                            ]
                        ],
                    ]
                ]
            ]
        );
    }

    //Implement the other methods you need
}

3 - Update your listing component. It must have a updateUrl parameter inside of the DataSource component:

(Vendor/Module/view/adminhtml/ui_component/vendor_module_listing.xml)

<?xml version="1.0" encoding="UTF-8"?>
<listing 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">
                vendor_module_listing.module_listing_data_source
            </item>
        </item>
    </argument>
    <settings>
        <spinner>vendor_module_listing_columns</spinner>
        <deps>
            <dep>vendor_module_listing.module_listing_data_source</dep>
        </deps>
    </settings>
    <dataSource name="module_listing_data_source">
        <argument name="dataProvider" xsi:type="configurableObject">
            <argument name="class" xsi:type="string">Vendor\Module\Ui\DataProvider\[name-of-your-listing-data-provider-class]</argument>
            <argument name="name" xsi:type="string">module_listing_data_source</argument>
            <argument name="primaryFieldName" xsi:type="string">id</argument>
            <argument name="requestFieldName" xsi:type="string">id</argument>
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/provider</item>
                    <item name="update_url" xsi:type="url" path="mui/index/render"/>
                    <item name="storageConfig" xsi:type="array">
                        <item name="indexField" xsi:type="string">id</item>
                    </item>
                    <!-- fields to be added to the URL when retrieving the data -->
                    <item name="filter_url_params" xsi:type="array">
                        <item name="id" xsi:type="string">*</item>
                    </item>
                </item>
            </argument>
        </argument>
    </dataSource>
    <columns name="vendor_module_listing_columns">

        <!-- Declare your columns here -->

    </columns>
</listing>

4 - Update your Listing Data Provider to change the updateUrl on the above listing component

(Vendor/Module/Ui/DataProvider/[path-to-your-LISTING-data-provider.php])

Note: do not copy/paste the entire block below on your Data Provider. Instead, cherrypick the pieces that are missing from your code

 <?php

    use Magento\Framework\App\RequestInterface;

    class MyListingDataProvider extends AbstractDataProvider
    {
        protected $request; 

        public function __construct(
            string $name,
            string $primaryFieldName,
            string $requestFieldName,
            Collection $collection,
            RequestInterface $request,
            array $meta = [],
            array $data = []
        )
        {
            $this->collection = $collection;
            $this->request = $request;
            $this->data = $data;

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

            $this->prepareUpdateUrl();
        }

        protected function prepareUpdateUrl()
        {
            if (!isset($this->data['config']['filter_url_params'])) {
                return;
            }

            foreach ($this->data['config']['filter_url_params']
                     as $paramName => $paramValue) {
                if ('*' == $paramValue) {
                    $paramValue = $this->request->getParam($paramName);
                }
                if ($paramValue) {
                    $this->data['config']['update_url'] = sprintf(
                        '%s%s/%s/',
                        $this->data['config']['update_url'],
                        $paramName,
                        $paramValue
                    );
                }
            }
        }

         //Get the parameter "id" inside of the getData() method:

        public function getData()
        {
        $item_id = $this->request->getParam('id');

        //Apply a filter to your collection using $item_id

        /**
        Return your data in the appropriate format
        $totalRecords should be an integer
        $items should be an array
        */
        return array('totalRecords' => $totalRecords, 'items' => $items);

        }

    }

Let me know if you still have any problems. I may not be able to answer on the comments but I can update my answer.

5
  • I can't seem to make this work, my parameter is always NULL. Can you help ?
    – Badong
    Oct 8, 2020 at 14:01
  • This is a bad workaround. You shouldn't use Request and all other stuff.
    – zhartaunik
    Apr 12, 2022 at 16:49
  • @zhartaunik Awesome! Please, feel free to enlighten us by providing a functional solution without "Request and all other stuff" 😉 Apr 13, 2022 at 15:18
  • @AndresaMartins yes, you were right. It's impossible to avoid REQUEST usage. But some of your steps are excess. The goal is to push an additional parameter to mui/index/renderer. I thought that it must be processed as a filter by default. But I was mistaken. However it's possible to push this param only using exports/imports section and this param appeared in the REQUEST. Then you must override DataProvider::getData() method, by adding $collection->addFieldToFilter('giftcard_id', $this->request->getParam('giftcard_id')); If you need, I can share my solution.
    – zhartaunik
    Apr 14, 2022 at 19:53
  • @zhartaunik You should post a new answer to the question and make sure it works. My response is from 2018 and whatever version I was using back then was outdated long ago. Apr 17, 2022 at 22:39
2

For add insert listing by param of parent ui-component we can use below code.

Here externalProvider tag is for add source provider of the listing which we are inserting.

Here imports tag is used for import param of the current form data source

Here exports tag is used for export the current form data params to the listing which going to be insert.

<insertListing name="insertlisting_colors_one">
    <argument name="data" xsi:type="array">
        <item name="config" xsi:type="array">
            <item name="autoRender" xsi:type="boolean">true</item>
            <item name="ns" xsi:type="string">colors_one_grid</item>
            <item name="externalProvider" xsi:type="string">colors_one_listing.colors_one_listing_data_source</item><!-- your insert listing data provider source -->
            <item name="imports" xsi:type="array">
                <item name="spd_id" xsi:type="string">${ $.provider }:data.spd_id</item>
            </item>
            <item name="exports" xsi:type="array">
                <item name="spd_id" xsi:type="string">${ $.externalProvider }:params.spd_id</item>
            </item>
        </item>
    </argument>
</insertListing>

Add join with relevant column to the current collection for make it use in filter the data provider of inserted listing.

In the data provider add filter for this param:

$collection->addFieldToFilter('spd_id', $this->request->getParam('spd_id'));
2
  • I have tried your example but it's not working do you have any idea why i am not getting parent id to grid provider ?
    – Deep Joshi
    Feb 10, 2020 at 10:46
  • 1
    This works for sure!
    – zhartaunik
    Apr 12, 2022 at 17:40
0

For anyone still struggling with this, here's what worked for me. I followed @andresa-martins ' answer, but with a twist.

I first noticed my meta was always empty on initialisation in my form dataprovider. I then researched a bit how to generally edit the meta, and found this post. Notice how they insert data in meta, with [<fieldset_name>]['children'][<field_name>], and directly inside an override of getMeta(). Well that's what worked for me. My form dataprovider now looks something like this:

<?php

namespace ...;

use Magento\Framework\App\RequestInterface;
use Magento\Backend\Model\UrlInterface;

use CollectionFactory;

class FormDataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
{
    /**
     * @var RequestInterface
     */
    private $_request;
    /**
     * @var UrlInterface
     */
    private $_urlBuilder;
    /**
     * @var array
     */
    private $_meta;

    /**
     * FormDataProvider constructor.
     * @param UrlInterface $urlBuilder
     * @param RequestInterface $requestInterface
     * @param string $name
     * @param string $primaryFieldName
     * @param string $requestFieldName
     * @param CommonCollectionFactory $collectionFactory
     * @param array $meta
     * @param array $data
     */
    public function __construct(
        UrlInterface $urlBuilder,
        RequestInterface $requestInterface,
        $name,
        $primaryFieldName,
        $requestFieldName,
        CommonCollectionFactory $collectionFactory,
        array $meta = [],
        array $data = []
    ) {
        $this->collection = $collectionFactory->create();
        $this->_urlBuilder = $urlBuilder;
        $this->_request = $requestInterface;

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

    public function getMeta()
    {
        $meta = parent::getMeta();
        $meta[<fieldset_name>]['children'][<insertListing_name>]['arguments']['data']['config']['render_url'] = $this->_urlBuilder
            ->getUrl('mui/index/render/id/'.$this->_request->getParam('id'));

        return $meta;
    }

    public function getData()
    {
        ...
    }
}

Now make sure you correctly followed step 1, 3 and 4 from this answer and you should be able to get the data you want to pass inside you listing dataprovider. Please let me know if you have any question.

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.