0

I have been struggling with this for a couple days now... I have created a module that add a new tab to the customer admin page.

It works fine when loading and displaying the information I need but when I use the filters to find a product it reloads the whole tab instead of just the current grid overwriting the whole container.

In short I have 1 controller to generate the page from the following layout

Morello\Customerproducts\view\adminhtml\layout\customerproducts_index_customer.xml

<?xml version="1.0"?>
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_generic.xsd">
    <container name="content" label="Root">

        <block class="\Morello\Customproducts\Block\Adminhtml\Edit\Page\Frame" name="customer_product_edit_frame"  template="Morello_Customproducts::frame.phtml">

            <block class="\Morello\Customproducts\Block\Adminhtml\Edit\Page\CustomerProducts" template="Morello_Customproducts::products.phtml" name="customer_products">
                <block class="\Morello\Customproducts\Block\Adminhtml\Edit\Page\CustomerProductsGrid" name="customer_products_grid" as="customer_products_grid" />
            </block>

            <block class="\Morello\Customproducts\Block\Adminhtml\Edit\Page\Search" template="Morello_Customproducts::search.phtml" name="customer_product_search">
                <block class="\Morello\Customproducts\Block\Adminhtml\Edit\Page\SearchProductGrid" name="customer_product_search_grid" as="customer_product_search_grid" />
            </block>

        </block>

    </container>

</layout>

As you can see I actually have 2 grids customer_products_grid and customer_product_search_grid for simplicity I will focus on the latter because I need to understand the process and I'll apply it to the former as well later on...

The grid module class file reference by \Morello\Customproducts\Block\Adminhtml\Edit\Page\SearchProductGrid contains the following

Morello\Customerproducts\Block\Adminhtml\Edit\Page\SearchProduct.php

<?php

namespace Morello\Customproducts\Block\Adminhtml\Edit\Page;

use Magento\Backend\Block\Template\Context;
use Magento\Backend\Helper\Data;
use Magento\Backend\Model\Session\Quote;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;

class SearchProductGrid extends \Magento\Backend\Block\Widget\Grid\Extended
{

    private $productCollectionFactory;
    private $sessionQuote;

    public function __construct(
        //...
    )
    {
        //...
    }

    protected function _construct()
    {
        //..
    }

    public function getStore()
    {
        //...
    }

    public function getProductCollection()
    {
        //...
    }

    protected function _prepareCollection()
    {
        //...
    }

    protected function _prepareColumns()
    {
        //...
        return parent::_prepareColumns();
    }

    /*************************************************************************/

    // I KNOW I HAVE TO USE THIS TO GET WHAT I WANT BUT I CAN'T FIGURE OUT HOW

    /*************************************************************************/
    public function getGridUrl()
    {
        return $this->getUrl(
            'customproducts/*/???', ['_current' => true, 'collapse' => null]
        );
    }

}

This is currently my ONLY controller

Morello\Customerproducts\Controller\Adminhtml\Index\Customer.php

class Customer extends \Magento\Customer\Controller\Adminhtml\Index
{
    public function execute()
    {
        $this->initCurrentCustomer();
        $resultLayout = $this->resultLayoutFactory->create();
        return $resultLayout;
    }
}

WHAT AM I MISSING?

Any help is appreciated, thanks guys.

1 Answer 1

3

Of course, as per usual, I figured it out right after posting my question... Argh... I'll post the solution since there is a frustrating lack of documentation about M2.

This part of my grid block file was modified as follows

public function getGridUrl()
{
    return $this->getUrl(
        'customproducts/*/reloadgrid', ['_current' => true, 'collapse' => null]
    );
}

the getUrl() method is given the path to a new controller I use to reload the grid (through customproducts/*/reloadgrid parameter).

Here is the content of the new controller

Morello/Customproducts/Controller/Adminhtml/Index/ReloadGrid.php

<?php

namespace Morello\Customproducts\Controller\Adminhtml\Index;

use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\ResponseInterface;
use Magento\Framework\Controller\Result\Raw;
use Magento\Framework\View\Result\PageFactory;

class ReloadGrid extends Action
{
// Let's get down to business, shall we?
    protected $resultPageFactory;
    protected $resultInterface;
    protected $resultRaw;

    /**********************************************************************
    *
    * In the construct I collect the info I'll need in the execute() method
    * namely the PageFactory, ResultPageFactory and Raw result to provide
    * the interface the method must return
    *
    ***********************************************************************/

    public function __construct(Context $context, PageFactory $resultPageFactory, Raw $resultRaw)
    {
        $this->resultPageFactory = $resultPageFactory;
        $this->resultRaw = $resultRaw;
        parent::__construct($context);
    }

    /**********************************************************************
    *
    * This is where it got tricky for me.
    * I'll walk through the steps one by one (because I wish someone would
    * have done it while I was searching for a solution...)
    *
    ***********************************************************************/

    public function execute()
    {   
        // First step is to create a ResultPageFactory
        // to retrieve the result for the filtered table
        $resultPage = $this->resultPageFactory->create();

        // In order to update the grid we can reload the original
        // block used to render it in the first place but if you
        // look at my question you'll see that my template file
        // 'customerproducts_index_customer.xml' has a nested
        // structure with the grid block/class already inside 
        // a couple of blocks, so rather than refactoring that
        // I created a new template just for reloading the grid
        // which I called 'customproducts_search_grid_handle.xml'
        // for simplicity. (content is attached below)

        // Second step is to provide the block to render to the 
        // ResultPageFactory we instantiated in step 1 by passing
        // our handle name
        $resultPage->addHandle('customproducts_search_grid_handle');

        // Once our ResultPageFactory knows what we want we can
        // Ask it to extract the layout and render the element 'content'
        $result = $resultPage->getLayout()->renderElement('content');

        // This was the trickiest step for me. Since the execute mthod
        // of Magento\Framework\App\Action\Action must return either
        // a ResultInterface or a ResponseInterface I needed to find
        // a class that would allow me to get the content in the desired
        // format so I used Magento\Framework\Controller\Result\Raw
        // which extends AbstractResult which extends ResultInterface
        // and then we can call the setContents() method providing
        // the element we rendered in the 3rd step...
        return $this->resultRaw->setContents($result);

        // Easy-Peasy right?
    }
}

Here is the content of the new layout for the handle

Morello/Customproducts/view/adminhtml/layout/customproducts_search_grid_handle.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="content">
            <block class="\Morello\Customproducts\Block\Adminhtml\Edit\Page\SearchProductGrid" name="customer_product_search_grid" as="customer_product_search_grid" />
        </referenceContainer>
    </body>
</page>

As you can see it just contains the instance of the block we already used when creating the grid the first time.

I hope this helps somebody avoiding a few days of despair.

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.