Magento – Magento 2 : How to load an admin grid with pre-defined filter values

adminfiltergridmagento2

I want to create a link to a custom grid in my admin with pre-defined filters. The grid is made with a UI Listing Component (XML) and it has a column called form_id that is setup like this:

<column name="form_id">
    <argument name="data" xsi:type="array">
        <item name="config" xsi:type="array">
            <item name="filter" xsi:type="string">textRange</item>
            <item name="label" xsi:type="string" translate="true">Form id</item>
        </item>
    </argument>
</column>

The grid works just fine. I can apply the filter and everything works well. The grid gets nicely updated with a XHR request.

However… I want to be able to have a filters' value pre-defined at some point. For example, I want to be able to open the grid when it's filtered on ID=3.

So I already tried loading the page with the same URL parameters as the XHR-request, as well as simply adding the only required parameters:

?namespace=form_response_listing&search=&filters[placeholder]=true&filters[form_id][from]=3&filters[form_id][to]=3&paging[pageSize]=20&paging[current]=1

As well as:

?filters[form_id][from]=3&filters[form_id][to]=3

Both with no success. So how Can I pre-fill filters by using the URL?

Edit:

I'm not sure if this is a duplicate of the other question (as mentioned in the comments below). In my case, I'm using a virtual type as collection for my grid:

<virtualType name="Vendor\Module\Model\ResourceModel\Response\Grid\Collection"
             type="Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult">
    <arguments>
        <argument name="mainTable" xsi:type="string">vendormodule_form_response</argument>
        <argument name="resourceModel" xsi:type="string">Vendor\Module\Model\ResourceModel\Response</argument>
    </arguments>
</virtualType>

So it's not that I have a physical Block class for my grid widget, it's purely created with a UI Component listing XML.

Nevertheless, I'll check anyway if the question referred to will help my use case.

Best Answer

Here is what I found out so far.
This is not complete but it can take you on the right path.
I conducted my tests by modifying the cms page listing ui component.
I added this

<item name="filter_url_params" xsi:type="array">
    <item name="page_id" xsi:type="string">*</item>
</item>

in cms_page_listing.xml inside the dataSource node inside the data/config argument. So now it looks like this

<dataSource name="cms_page_listing_data_source">
    <argument name="dataProvider" xsi:type="configurableObject">
        <argument name="class" xsi:type="string">Magento\Cms\Ui\Component\DataProvider</argument>
        <argument name="name" xsi:type="string">cms_page_listing_data_source</argument>
        <argument name="primaryFieldName" xsi:type="string">page_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">page_id</item>
                </item>
                <item name="filter_url_params" xsi:type="array"><!-- my addition -->
                    <item name="page_id" xsi:type="string">*</item>
                </item>
            </item>
        </argument>
    </argument>
</dataSource>

This allows me to call the url ROOT/admin/cms/page/index/key/<form_key_here>/?page_id=2.
And I see only the page with id 2.
But it does not work for range filters and the filter value is not filled in. It still shows as blank.

Now here is why this is possible.

The dataProvider class for cms pages is Magento\Cms\Ui\Component\DataProvider.
This one extends Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider.
This last one contains a protected method called 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
            );
            $this->addFilter(
                $this->filterBuilder->setField($paramName)->setValue($paramValue)->setConditionType('eq')->create()
            );
        }
    }
}

What this does is to check in the ui component config if there is an element called filter_url_params. If there is, it takes all the values inside it and checks the request for values matching what's defined in filter_url_params.
But by default it works only with eq.

What you can try is to have a custom dataSource for your component where you rewrite the method prepareUpdateUrl and make it take into account all the request variables you need and maybe add paging to it and range filtering.

Side note: This is a very interesting question. I'm sure a lot of people will need this in the future.

Related Topic