Magento2 Customer Tab – Can’t Get Grid Post Values

customergrid-serlizationmagento2

I'm trying to make an grid in customer, but I can't get the post of this grid.

What's is wrong?

Here is my config xml

\Vendor\Rep\view\adminhtml\layout

customer_index_edit.xml

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-2columns-left"
  xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd">
<body>
    <referenceBlock name="customer_form">
        <block class="Vendor\Rep\Block\Adminhtml\Customer\Edit\Tab\Rep" name="customer_edit_tab_rep">
            <action method="setTabLabel">
                <argument name="label" xsi:type="string">Sales Representative</argument>
            </action>
        </block>
    </referenceBlock>
</body>

vendor_rep_customer_rep.xml

<?xml version="1.0"?>
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/layout_generic.xsd">
<container name="root" label="Root">
    <block class="Vendor\Rep\Block\Adminhtml\Customer\Edit\Tab\Rep\Grid" name="customer.edit.tab.rep.grid"/>
    <block class="Magento\Backend\Block\Widget\Grid\Serializer" name="related_grid_serializer">
        <arguments>
            <argument name="grid_block" xsi:type="string">customer.edit.tab.rep.grid</argument>
            <argument name="callback" xsi:type="string">getSelectedReps</argument>
            <argument name="input_element_name" xsi:type="string">reps_ids</argument>
            <argument name="reload_param_name" xsi:type="string">reps</argument>
        </arguments>
    </block>
</container>

Here is my tab and grid classes

\Vendor\Rep\Block\Adminhtml\Customer\Edit\Tab\Rep.php

namespace Vendor\Rep\Block\Adminhtml\Customer\Edit\Tab;

use Magento\Customer\Controller\RegistryConstants;
use Magento\Ui\Component\Layout\Tabs\TabInterface;

/**
 * Customer account form block
 */
class Rep extends \Magento\Backend\Block\Template implements TabInterface
{
    /**
     * Core registry
     *
     * @var \Magento\Framework\Registry
     */
    protected $_coreRegistry;
    /**
     * @param \Magento\Backend\Block\Template\Context $context
     * @param \Magento\Framework\Registry $registry
     * @param array $data
     */
    public function __construct(
        \Magento\Backend\Block\Template\Context $context,
        \Magento\Framework\Registry $registry,
        array $data = []
    ) {
        $this->_coreRegistry = $registry;
        parent::__construct($context, $data);
    }
    /**
     * @return string|null
     */
    public function getCustomerId()
    {
        return $this->_coreRegistry->registry(RegistryConstants::CURRENT_CUSTOMER_ID);
    }
    /**
     * @return \Magento\Framework\Phrase
     */
    public function getTabLabel()
    {
        return __('Sales Representative');
    }
    /**
     * @return \Magento\Framework\Phrase
     */
    public function getTabTitle()
    {
        return __('Sales Representative');
    }
    /**
     * @return bool
     */
    public function canShowTab()
    {
        if ($this->getCustomerId()) {
            return true;
        }
        return false;
    }

    /**
     * @return bool
     */
    public function isHidden()
    {
        if ($this->getCustomerId()) {
            return false;
        }
        return true;
    }
    /**
     * Tab class getter
     *
     * @return string
     */
    public function getTabClass()
    {
        return '';
    }
    /**
     * Return URL link to Tab content
     *
     * @return string
     */
    public function getTabUrl()
    {
        return $this->getUrl('vendor_rep/customer/rep', ['_current' => true]);
    }
    /**
     * Tab should be loaded trough Ajax call
     *
     * @return bool
     */
    public function isAjaxLoaded()
    {
        return false;
    }
}

\Vendor\Rep\Block\Adminhtml\Customer\Edit\Tab\Rep\Grid.php

namespace Vendor\Rep\Block\Adminhtml\Customer\Edit\Tab\Rep;

use Magento\Customer\Controller\RegistryConstants;

/**
 * Adminhtml customer recent orders grid block
 */
class Grid extends \Magento\Backend\Block\Widget\Grid\Extended
{
    /**
     * @var \Magento\Customer\Model\Customer
     */
    protected $_customer = null;

    /**
     * @var \Magento\Customer\Model\CustomerFactory
     */
    protected $_customerFactory = null;

    /**
     * Core registry
     *
     * @var \Magento\Framework\Registry|null
     */
    protected $_coreRegistry = null;

    /**
     * @var \Vendor\Rep\Model\Resource\Rep\CollectionFactory
     */
    protected $_repCollectionFactory;

    /**
     * @var \Vendor\Rep\Helper\Customer
     */
    protected $_customerHelper;

    /**
     * Constructor
     *
     * @param \Magento\Backend\Block\Template\Context $context
     * @param \Magento\Framework\Registry $coreRegistry
     * @param \Magento\Customer\Model\CustomerFactory $customerFactory
     * @param \Magento\Backend\Helper\Data $backendHelper
     * @param \Vendor\Rep\Model\Resource\Rep\CollectionFactory $repCollectionFactory
     * @param \Vendor\Rep\Helper\Customer $customerHelper
     * @param array $data
     */
    public function __construct(
        \Magento\Backend\Block\Template\Context $context,
        \Magento\Framework\Registry $coreRegistry,
        \Magento\Backend\Helper\Data $backendHelper,
        \Magento\Customer\Model\CustomerFactory $customerFactory,
        \Vendor\Rep\Model\Resource\Rep\CollectionFactory $repCollectionFactory,
        \Vendor\Rep\Helper\Customer $customerHelper,
        array $data = []
    ) {
        $this->_coreRegistry = $coreRegistry;
        $this->_repCollectionFactory = $repCollectionFactory;
        $this->_customerHelper = $customerHelper;
        $this->_customerFactory = $customerFactory;
        parent::__construct($context, $backendHelper, $data);
    }

    /**
     * Initialize the grid.
     *
     * @return void
     */
    protected function _construct()
    {
        parent::_construct();
        $this->setId('customer_edit_tab_rep_grid');
        $this->setDefaultSort('name');
        $this->setDefaultDir('asc');
        $this->setUseAjax(true);
        /*if ($this->getCustomer() && $this->getCustomer()->getId()) {
            $this->setDefaultFilter(['in_reps' => 1]);
        }*/
    }

    /**
     * Retrieve currently edited product model
     *
     * @return array|null
     */
    public function getCustomer()
    {
        if (!$this->_customer || !$this->_customer->getId()) {
            $this->_customer = $this->_customerFactory->create()->load($this->_coreRegistry->registry(RegistryConstants::CURRENT_CUSTOMER_ID));
        }

        return $this->_customer;
    }

    /**
     * Add filter
     *
     * @param Column $column
     * @return $this
     */
    protected function _addColumnFilterToCollection($column)
    {
        // Set custom filter for in product flag
        if ($column->getId() == 'in_reps') {
            $repIds = $this->_getSelectedReps();
            if (empty($repIds)) {
                $repIds = 0;
            }
            if ($column->getFilter()->getValue()) {
                $this->getCollection()->addFieldToFilter('main_table.rep_id', ['in' => $repIds]);
            } else {
                if ($repIds) {
                    $this->getCollection()->addFieldToFilter('main_table.rep_id', ['nin' => $repIds]);
                }
            }
        } else {
            parent::_addColumnFilterToCollection($column);
        }
        return $this;
    }

    /**
     * {@inheritdoc}
     */
    protected function _prepareCollection()
    {
        $collection = $this->_repCollectionFactory->create();

        if ($this->getCustomer()->getId()) {
            $constraint = 'related.customer_id='.$this->getCustomer()->getId();
        } else {
            $constraint = 'related.customer_id=0';
        }
        $collection->getSelect()->joinLeft(
            array('related' => $collection->getTable('vendor_rep_customer')),
            'related.rep_id=main_table.rep_id AND '.$constraint,
            array('position')
        );

        $this->setCollection($collection);
        return parent::_prepareCollection();
    }

    /**
     * {@inheritdoc}
     */
    protected function _prepareColumns()
    {
        $this->addColumn(
            'in_reps',
            [
                'type' => 'checkbox',
                'name' => 'in_reps',
                'values' => $this->_getSelectedReps(),
                'align' => 'center',
                'index' => 'rep_id',
                'header_css_class' => 'col-select',
                'column_css_class' => 'col-select'
            ]
        );
        $this->addColumn(
            'rep_id',
            [
                'header' => __('ID'),
                'sortable' => true,
                'index' => 'rep_id',
                'header_css_class' => 'col-id',
                'column_css_class' => 'col-id'
            ]
        );
        $this->addColumn(
            'name',
            [
                'header' => __('Name'),
                'index' => 'name',
                'header_css_class' => 'col-name',
                'column_css_class' => 'col-name'
            ]
        );
        return parent::_prepareColumns();
    }

    /**
     * Retrieve selected related reps
     *
     * @return array
     */
    protected function _getSelectedReps()
    {
        $reps = $this->getCustomerReps();
        if (!is_array($reps)) {
            $reps = array_keys($this->getSelectedReps());
        }
        return $reps;
    }

    /**
     * Retrieve related reps
     *
     * @return array
     */
    public function getSelectedReps()
    {
        $reps = [];

        $selected = $this->_customerHelper->getSelectedReps($this->getCustomer());
        if (!is_array($selected)) {
            $selected = [];
        }
        foreach ($selected as $rep) {
            //$salesreps[$salesrep->getId()] = array('position' => $salesrep->getPosition());
            $reps[$rep->getId()] = array('position' => 0);
        }

        return $reps;
    }

    /**
     * Rerieve grid URL
     *
     * @return string
     */
    public function getGridUrl()
    {
        return $this->getData(
            'grid_url'
        ) ? $this->getData(
            'grid_url'
        ) : $this->getUrl(
            'vendor_rep/customer/rep',
            ['_current' => true]
        );
    }   

}

Here is my event

\Vendor\Rep\etc\adminhtml\events.xml

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../lib/internal/Magento/Framework/Event/etc/events.xsd">
    <event name="adminhtml_customer_save_after">
        <observer name="vendor_rep_save_customer_reps" instance="Vendor\Rep\Observer\SaveCustomerReps" />
    </event>
</config>

And here I have an var_dump only to test the post.

\Vendor\Rep\Observer\SaveCustomerReps.php

namespace Vendor\Rep\Observer;

use Magento\Framework\Event\ObserverInterface;

class SaveCustomerReps implements ObserverInterface
{
    /**
     * Catalog data
     *
     * @var \Magento\Catalog\Helper\Data
     */
    protected $catalogData;

    /**
     * @param \Magento\Catalog\Helper\Data $catalogData
     */
    public function __construct(
        \Magento\Framework\App\ResourceConnection $resource
    )
    {
        $this->_resource = $resource;
    }

    /**
     * Checking whether the using static urls in WYSIWYG allowed event
     *
     * @param \Magento\Framework\Event\Observer $observer
     * @return void
     */
    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        var_dump($_POST);
    }
}

Best Answer

There can be 2 possible problems:

  1. First please make sure if your grid values are populated correctly: if you inspect HTML source below your grid, you should have hidden input with names that represent your config XML input field (in your case it should be like: <input type="hidden" name="reps_ids" value="" id="id_SOME_GENERATED_VALUE_HERE">.
    First of all, make sure when you select something on the grid -> this field should be modified, and value should be updated. If data is not populated, make sure that your grid config is correct.

  2. If the first problem is solved (or does not exists) and values are in hidden field, but are not sent with post, the problem is probably because your grid is not registered as a part of customer_form (it is not declared inside customer_form.xml). If you will take a look inside form.js to see how Magento handle the form you will see something here:

    vendor/magento/module-ui/view/base/web/js/form/form.js:277
    

    There is a selector for additional fields that can be taken into the form submit. If you will debug this you will notice that additionalFields selector take anything into submit that contain "form" attribute, so if you will manage to make your hidden input to contain attribute: form="customer_form", then your values should be posted with customer form. So your input should look like:

    <input type="hidden" name="reps_ids" value="" id="id_SOME_GENERATED_VALUE_HERE" form="customer_form">
    

    You can do it by overriding widget/grid/serializer.phtml for your grid only or by overriding the proper block and setting this param through it.

Related Topic