How to pass data to another ui components DataProvider

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="slide_grid">
    <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">slide_grid</item><-- data source of the inserted listing -->
            <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.slider_id</item>
            </item>
            <item name="exports" xsi:type="array">
                <item name="slider_id" xsi:type="string">${ $.externalProvider }:params.slider_id</item>
            </item>
        </item>
    </argument>
</insertListing>

Add join with relevant column to the current collection for make it use in two ways:

  1. Filter by grid dataSource > argument name > "dataProvider" > argument name > "data" > item name "config" > item name="filter_url_params" => item name > "slider_id".

For more detail check below code:

<dataSource name="..._listing_data_source">
    <argument name="dataProvider" xsi:type="configurableObject">
        <argument name="class" xsi:type="string">...\...\Ui\DataProvider\...\Grid\...DataProvider</argument>
        <argument name="name" xsi:type="string">..._listing_data_source</argument>
        <argument name="primaryFieldName" xsi:type="string">id</argument>
        <argument name="requestFieldName" xsi:type="string">slider_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="filter_url_params" xsi:type="array">
                    <item name="slider_id" xsi:type="string">*</item>
                </item>
                <item name="storageConfig" xsi:type="array">
                    <item name="indexField" xsi:type="string">id</item>
                </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/grid/provider</item>
        </item>
    </argument>
</dataSource>
  1. Filter the data provider of inserted listing.

In the data provider add filter for this param:

$collection->addFieldToFilter('slider_id', $this->request->getParam('slider_id'));

I like to follow option 1.


After reading and debugging the Magento 2 core files I have found a clean and simple solution about this issue. Passing data from a custom form to a custom grid using the UIComponent insertListing is really hard and not documented at all.

enter image description here

The InsertListing object has two parameters under the tag: exports and imports that I have used in my listing:

<fieldset name="relatedto" >
    <settings>
        <label>Related to</label>
        <componentType>fieldset</componentType>
    </settings>

    <insertListing name="threadrelated_listing">
        <settings>
            <dataLinks>
                <exports>false</exports>
                <imports>true</imports>
            </dataLinks>
            <externalProvider>mycompany_helpdesk_threadrelated_listing.mycompany_helpdesk_threadrelated_listing_data_source</externalProvider>
            <selectionsProvider>mycompany_helpdesk_threadrelated_listing.mycompany_helpdesk_threadrelated_listing.mycompany_helpdesk_threadrelated_columns.ids</selectionsProvider>
            <autoRender>true</autoRender>
            <dataScope>mycompany_helpdesk_threadrelated_listing</dataScope>
            <ns>mycompany_helpdesk_threadrelated_listing</ns>
            <exports>
                <link name="ticket_id">${ $.externalProvider }:params.ticket_id</link>
            </exports>
            <imports>
                <link name="ticket_id">${ $.provider }:data.ticket_id</link>
            </imports>
        </settings>
    </insertListing>
</fieldset>

and after hours to understand and find a solution on the web, I have not found any clue!

So I have read the Magento Core file and I have discovered that Magento meshups the way to create the nested listing grids in the project. Sometime it uses the old block insert method and few times the new UIComponent listing method.

I have found the customer address listing grid at the customer_address_listing.xml (/vendor/magento/module-customer/view/adminhtml/ui_component/customer_address_listing.xml) and it gets the parent_id variable defined in the customer_form.xml (/vendor/magento/module-customer/view/base/ui_component/customer_form.xml) but the question is:

How Magento pass the data from the form to the nested listing grid?

Magento pass the data by the QUERYSTRING PARAMETER!

If you read the DataProvider.php file you will be surprised because it gets the parent_id (customer) variable by the QUERYSTRING! Look at /vendor/magento/module-customer/Ui/Component/Listing/Address/DataProvider.php line 58:

/**
 * Add country key for default billing/shipping blocks on customer addresses tab
 *
 * @return array
 */
public function getData(): array
{
    $collection = $this->getCollection();
    $data['items'] = [];
    if ($this->request->getParam('parent_id')) {
        $collection->addFieldToFilter('parent_id', $this->request->getParam('parent_id'));
        $data = $collection->toArray();
    }
    foreach ($data['items'] as $key => $item) {
        if (isset($item['country_id']) && !isset($item['country'])) {
            $data['items'][$key]['country'] = $this->countryDirectory->loadByCode($item['country_id'])->getName();
        }
    }

    return $data;
}

but how do I set the parameter in the listinggrid URL? I have found the filterUrlParams parameter but there is an odd issue also here! Let take a look at this snipped of dataSource code:

<dataSource name="mycompany_helpdesk_threadrelated_listing_data_source" component="Magento_Ui/js/grid/provider">
    <settings>
        <filterUrlParams>
            <param name="ticket_id">*</param>
        </filterUrlParams>
        <storageConfig>
            <param name="indexField" xsi:type="string">threadrelated_id</param>
        </storageConfig>
        <updateUrl path="mui/index/render"/>
    </settings>
    <dataProvider class="mycompany\Helpdesk\Ui\DataProvider\Threadrelated\ThreadRelatedDataProvider" name="mycompany_helpdesk_threadrelated_listing_data_source">
        <settings>
            <requestFieldName>id</requestFieldName>
            <primaryFieldName>threadrelated_id</primaryFieldName>
        </settings>
    </dataProvider>
</dataSource>

I have set the ticket_id with a wildcard (*) that it means: get all the tickets! but if you do not set any ID in the filterUrlParams the insertListing URL has NOT ANY ticket_id SET! So why?!

The solution offered by @hashish-raj doesn't work for me.

These are all the post that I have read about this issue:

  • Add default filter to sales_order_grid for order status
  • Filter admin grid based on the url parameter
  • Filtering grid by using filter_url_params is not working
  • How to pass data to another ui components DataProvider
  • Filter Collection of Listing depends on Request Parameter
  • Magento2 send ID insertListing to grid
  • Magento 2: How to link an admin form and list UI component via insertListing?

At the end I have found a temporary workaround using the core session and store the ticket_id parameter in the session. Then in the custom dataprovider I have check it and I have applied it to the collection:

/***
 * @return array
 */
public function getData()
{

    $collection = $this->getSearchResult();

    /** see: check Mycompany\Helpdesk\Controller\Adminhtml\Ticket\Edit **/
    if($this->coreSession->getTicketId()){
        $collection->addFieldToFilter('ticket_id', ['eq' => $this->coreSession->getTicketId()]);
    }

    return $this->searchResultToOutput($collection);

}

If you have a workaround or you have understood how Magento handles this relationship between the UIComponent, please share your knowledge!

I have opened a "bounty" here: https://magento.stackexchange.com/a/306537/2004