3

I have created a insertListing grid inside fieldset, Now I want to save id of checked grid items inside my custom collection field news_ids

I get this data in save controller params

enter image description here

But I am not getting this Listing item ids in save controller params

enter image description here

I am using insertListing below code, I don't know what problem occurs here

<insertListing name="testListingInsert">
                <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">vtn_newsticker_listing</item>
                        <item name="externalProvider" xsi:type="string">vtn_newsticker_listing.vtn_newsticker_listing_data_source</item>
                        <item name="imports" xsi:type="array">
                            <item name="news_ids" xsi:type="string">${ $.provider }:data.news_ids</item>
                        </item>
                        <item name="exports" xsi:type="array">
                            <item name="news_ids" xsi:type="string">${ $.externalProvider }:params.news_ids</item>
                        </item>
                    </item>
                </argument>
            </insertListing>

This is namespace for form

<item name="config" xsi:type="array">
            <item name="dataScope" xsi:type="string">data</item>
            <item name="namespace" xsi:type="string">vtn_newsticker_group_edit</item>
        </item>

And I am using this fieldset for getting grid

<fieldset name="assign_news">
            <settings>
                <collapsible>true</collapsible>
                <label translate="true">News in Group</label>
            </settings>
            <container name="news_ids_container" sortOrder="160">
                <htmlContent name="html_content">
                    <block name="assignnews" class="Vtn\NewsTicker\Block\Adminhtml\Newsids\AssignNews"/>
                </htmlContent>
            </container>
        </fieldset>

Below is code of this file Vtn\NewsTicker\Block\Adminhtml\Newsids\AssignNews

<?php
namespace Vtn\NewsTicker\Block\Adminhtml\Newsids;

class AssignNews extends \Magento\Backend\Block\Template
{
   /**
     * Block template
     *
     * @var string
     */
    protected $_template = 'newsgroup/assign_news.phtml';

    /**
     * @var \Magento\Catalog\Block\Adminhtml\Category\Tab\Product
     */
    protected $blockGrid;

    /**
     * @var \Magento\Framework\Registry
     */
    protected $registry;

    /**
     * @var \Magento\Framework\Json\EncoderInterface
     */
    protected $jsonEncoder;

    /**
     * @var Vtn\NewsTicker\Model\GroupFactory $groupFactory
     */
    protected $groupFactory;

    public function __construct(
        \Magento\Backend\Block\Template\Context $context,
        \Magento\Framework\Registry $registry,
        \Magento\Framework\Json\EncoderInterface $jsonEncoder,
        \Vtn\NewsTicker\Model\GroupFactory $groupFactory,
        array $data = []
    ) {
        $this->registry = $registry;
        $this->jsonEncoder = $jsonEncoder;
        $this->groupFactory = $groupFactory;
        parent::__construct($context, $data);
    }

    public function getBlockGrid()
    {
        if (null === $this->blockGrid) {
            $this->blockGrid = $this->getLayout()->createBlock(
                \Vtn\NewsTicker\Block\Adminhtml\Group\Tab\News::class,
                'news.grid'
            );
        }
        return $this->blockGrid;
    }

    /**
     * Return HTML of grid block
     *
     * @return string
     */
    public function getGridHtml()
    {
        return $this->getBlockGrid()->toHtml();
    }
    
    /**
     * @return string
     */
    //public function getNewsJson() {

    //    $id = $this->getRequest()->getParam('id');
     //   $groupFactory = $this->groupFactory->create()->load($id);
        
      //  if (isset($groupFactory)) {
      //      $result = $groupFactory['id'];
      //      $result = explode(',', $result);
       //     return $this->jsonEncoder->encode($result);
       // }
       // return '{}';
    //}


public function getNewsJson()
    {
        $id = $this->getRequest()->getParam('id');
        $groupNewsId = $this->groupFactory->create()
                                          ->getCollection()
                                          ->addFieldToFilter('id',$id)
                                          ->getColumnValues('news_ids');
        
        if (!empty($groupNewsId)) {
            return $this->jsonEncoder->encode($groupNewsId);
        }
        return '{}';
    }
    }

Below code of Vtn\NewsTicker\Block\Adminhtml\Group\Tab\News

<?php
namespace Vtn\NewsTicker\Block\Adminhtml\Group\Tab;
    
use Magento\Backend\Block\Widget\Grid;
use Magento\Backend\Block\Widget\Grid\Column;
use Magento\Backend\Block\Widget\Grid\Extended;
use Magento\Framework\App\ObjectManager;

class News extends \Magento\Backend\Block\Widget\Grid\Extended
{
    /**
     * Core registry
     *
     * @var \Magento\Framework\Registry
     */
    protected $_coreRegistry = null;

    /**
     * @var Vtn\NewsTicker\Model\GroupFactory $newsFactory
     */
    protected $newsFactory;

    /**
     * @param \Magento\Backend\Block\Template\Context $context
     * @param \Magento\Backend\Helper\Data $backendHelper
     * @param \Vtn\NewsTicker\Model\GroupFactory $newsFactory
     * @param \Magento\Framework\Registry $coreRegistry
     * @param array $data
     */
    public function __construct(
        \Magento\Backend\Block\Template\Context $context,
        \Magento\Backend\Helper\Data $backendHelper,
        \Magento\Framework\Registry $coreRegistry,
        \Vtn\NewsTicker\Model\NewsFactory $newsFactory,
        array $data = []
    ) {
        $this->newsFactory = $newsFactory;
        $this->_coreRegistry = $coreRegistry;
        parent::__construct($context, $backendHelper, $data);
    }

    /**
     * @return void
     */
    protected function _construct()
    {
        parent::_construct();
        $this->setId('group_news');
        $this->setDefaultSort('id');
        $this->setUseAjax(true);
    }

    /**
     * @return $this
     */

    protected function _prepareCollection()
    {
        $collection = $this->newsFactory->create()->getCollection();
        $this->setCollection($collection);
        return parent::_prepareCollection();
    }

    protected function _prepareColumns()
    {
        $this->addColumn(
            'in_news',
            [
                'type' => 'checkbox',
                'name' => 'in_news_ids',
                'values' => $this->_getSelectedNews(),
                'index' => 'id',
                'header_css_class' => 'col-select col-massaction',
                'column_css_class' => 'col-select col-massaction'
            ]
        );
        $this->addColumn(
            'id',
            [
                'header' => __('ID'),
                'sortable' => true,
                'index' => 'id',
                'header_css_class' => 'col-id',
                'column_css_class' => 'col-id'
            ]
        );
        $this->addColumn(
            'news_content', 
            [
                'header' => __('News'), 
                'index' => 'news_content'
            ]
        );
        $this->addColumn(
            'status', 
            [
                'header' => __('Active'), 
                'index' => 'status',
                'type'=>'options',
                'options' => array('1' => 'Yes', '0' => 'No')
            ]
        );
        
        return parent::_prepareColumns();
    }

    /**
     * @return string
     */
    public function getGridUrl()
    {
        return $this->getUrl('newsticker/group/edit', ['_current' => true]);
    }

    /**
     * @return array
     */
    protected function _getSelectedNews()
    {
        $news = $this->getRequest()->getPost('selected_news');
        return $news;
    }
}

Below is phtml code Vtn\NewsTicker\view\adminhtml\templates\newsgroup\assign_news.phtml

<?php
/** @var \Vtn\NewsTicker\Block\Template $block */

/** @var \Magento\Catalog\Block\Adminhtml\Category\AssignProducts $block */
/** @var \Magento\Catalog\Block\Adminhtml\Category\Tab\Product $blockGrid */
/** @var \Magento\Framework\View\Helper\SecureHtmlRenderer $secureRenderer */

$blockGrid = $block->getBlockGrid();
$gridJsObjectName = $blockGrid->getJsObjectName();

?>
<?= $block->getGridHtml() ?>
<input type="hidden" name="news_ids" id="in_news_ids" data-form-part="vtn_newsticker_group_edit" value="" />

<script type="text/x-magento-init">
    {
        "*": {
            "Vtn_NewsTicker/js/newsgroup/assign-news": {
                "selectedNews":  <?= /* @escapeNotVerified */ $block->getNewsJson() ?>,
                "gridJsObjectName": <?= /* @escapeNotVerified */ '"' . '$gridJsObjectName' . '"' ?: '{}' ?>
            }
        }
    }
</script>
<script>
    require('mage/apply/main').apply();
</script>

Below is assign_news.js

    define([
    'mage/adminhtml/grid'
], function () {
    'use strict';

    return function (config) {
        var selectedNews = config.selectedNews,
            categoryNews = $H(selectedNews),
            gridJsObject = window[config.gridJsObjectName],
            tabIndex = 1000;
        /**
         * Show selected news when edit form in associated news grid
         */
        $('in_news_ids').value = Object.toJSON(categoryNews); // add your hidden field id
        /**
         * Register Category Product
         *
         * @param {Object} grid
         * @param {Object} element
         * @param {Boolean} checked
         */
        function registerCategoryNews(grid, element, checked) {
            if (checked) {
                if (element.positionElement) {
                    element.positionElement.disabled = false;
                    categoryNews.set(element.value, element.positionElement.value);
                }
            } else {
                if (element.positionElement) {
                    element.positionElement.disabled = true;
                }
                categoryNews.unset(element.value);
            }
            $('in_news_ids').value = Object.toJSON(categoryNews); // add your hidden field id
            grid.reloadParams = {
                'selected_news[]': categoryNews.keys()
            };
        }

        /**
         * Click on news row
         *
         * @param {Object} grid
         * @param {String} event
         */
        
        function categoryNewsRowClick(grid, event) {
            var trElement = Event.findElement(event, 'tr'),
                eventElement = Event.element(event),
                isInputCheckbox = eventElement.tagName === 'INPUT' && eventElement.type === 'checkbox',
                isInputPosition = grid.targetElement &&
                    grid.targetElement.tagName === 'INPUT' &&
                    grid.targetElement.name === 'position',
                checked = false,
                checkbox = null;

            if (eventElement.tagName === 'LABEL' &&
                trElement.querySelector('#' + eventElement.htmlFor) &&
                trElement.querySelector('#' + eventElement.htmlFor).type === 'checkbox'
            ) {
                event.stopPropagation();
                trElement.querySelector('#' + eventElement.htmlFor).trigger('click');

                return;
            }

            if (trElement && !isInputPosition) {
                checkbox = Element.getElementsBySelector(trElement, 'input');

                if (checkbox[0]) {
                    checked = isInputCheckbox ? checkbox[0].checked : !checkbox[0].checked;
                    gridJsObject.setCheckboxChecked(checkbox[0], checked);
                }
            }
        }

        /**
         * Change news position
         *
         * @param {String} event
         */
        function positionChange(event) {
            var element = Event.element(event);

            if (element && element.checkboxElement && element.checkboxElement.checked) {
                categoryNews.set(element.checkboxElement.value, element.value);
                $('in_news_ids').value = Object.toJSON(categoryNews); // add your hidden field id
            }
        }

        /**
         * Initialize category news row
         *
         * @param {Object} grid
         * @param {String} row
         */
        function categoryNewsRowInit(grid, row) {
            var checkbox = $(row).getElementsByClassName('checkbox')[0],
                position = $(row).getElementsByClassName('input-text')[0];

            if (checkbox && position) {
                checkbox.positionElement = position;
                position.checkboxElement = checkbox;
                position.disabled = !checkbox.checked;
                position.tabIndex = tabIndex++;
                Event.observe(position, 'keyup', positionChange);
            }
        }

        gridJsObject.rowClickCallback = categoryNewsRowClick;
        gridJsObject.initRowCallback = categoryNewsRowInit;
        gridJsObject.checkboxCheckCallback = registerCategoryNews;

        if (gridJsObject.rows) {
            gridJsObject.rows.each(function (row) {
                categoryNewsRowInit(gridJsObject, row);
            });
        }
    };
});

1 Answer 1

1

To answer to your question, I will describe how the category backend form handles the problem you are trying to resolve. I am confident if each part of the description I make below are clear with you, then you will see what is the problem in your code.

To start, I suggest you may first open the following file:

vendor/magento/module-catalog/view/adminhtml/ui_component/category_form.xml

Particularly, both areas below:

<settings>
        <buttons>
            <button name="save" class="Magento\Catalog\Block\Adminhtml\Category\Edit\SaveButton"/>
            <button name="delete" class="Magento\Catalog\Block\Adminhtml\Category\Edit\DeleteButton"/>
        </buttons>
        <namespace>category_form</namespace>
        <dataScope>data</dataScope>
        <deps>
            <dep>category_form.category_form_data_source</dep>
        </deps>
    </settings>

--> in this area, the namespace will be the name of your form that will get posted to your controller. Therefore, the input field that will capture your table value will need to use this namespace

Second area to check below:

<fieldset name="assign_products" sortOrder="40">
        <settings>
            <collapsible>true</collapsible>
            <label translate="true">Products in Category</label>
        </settings>
        <container name="assign_products_container" sortOrder="160">
            <htmlContent name="html_content">
                <block name="gallery" class="Magento\Catalog\Block\Adminhtml\Category\AssignProducts"/>
            </htmlContent>
        </container>
    </fieldset>

--> this area will tell you what draws the table. It is likely you already know this part but I see this as an important point here

then, you also might want to check the file:

vendor/magento/module-catalog/view/adminhtml/templates/catalog/category/edit/assign_products.phtml

--> this template is the nerd of our problem I believe: you will find a hidden field and the value for data-form-part needs to match the namespace I mention above.

and finally:

vendor/magento/module-catalog/view/adminhtml/web/catalog/category/assign-products.js

--> this file feeds the hidden input and I suspect you got this already

UPDATED ANSWER: In your answer, this line should be "gridJsObjectName": <?= /* @escapeNotVerified */ '"' . '$gridJsObjectName' . '"' ?: '{}' ?> should be

"gridJsObjectName": <?= /* @escapeNotVerified */ '"' . $gridJsObjectName . '"' ?: '{}' ?>

Also, the code that displays the table is:

<fieldset name="assign_products" sortOrder="40">
        <settings>
            <collapsible>true</collapsible>
            <label translate="true">Products in Category</label>
        </settings>
        <container name="assign_products_container" sortOrder="160">
            <htmlContent name="html_content">
                <block name="gallery" class="Magento\Catalog\Block\Adminhtml\Category\AssignProducts"/>
            </htmlContent>
        </container>
    </fieldset>

whereas your code uses a node <insertListing..

Finally, your node where you define the namespace is also different to the file category_form.xml

 <settings>
        <buttons>
            <button name="save" class="Magento\Catalog\Block\Adminhtml\Category\Edit\SaveButton"/>
            <button name="delete" class="Magento\Catalog\Block\Adminhtml\Category\Edit\DeleteButton"/>
        </buttons>
        <namespace>category_form</namespace>
        <dataScope>data</dataScope>
        <deps>
            <dep>category_form.category_form_data_source</dep>
        </deps>
    </settings>

Your code may be not having problem as it is. However, the one I did try on my local is as per my above comments and of course this is what I can help you with. Good luck

UPDATE: I have written a backend screen that shows a finished table that propagates the table data to the controller. the repository is public and you can use it to troubleshoot your issue: backend screen repo

10
  • Thanks for the explanation I have done this yesterday but not getting selected values in thehidden field, I didn't get the issue Apr 27, 2021 at 3:43
  • I updated my question as per grid is showing in form but selected items id is not getting in db Apr 27, 2021 at 3:58
  • this line should be "gridJsObjectName": <?= /* @escapeNotVerified */ '"' . '$gridJsObjectName' . '"' ?: '{}' ?> Apr 27, 2021 at 8:02
  • Actually I am getting data from db in hidden values, I want selected value get update on select in values Apr 27, 2021 at 8:13
  • good, so your problem is more than likely the namespace Apr 27, 2021 at 8:15

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.