5

Is there an easy way to use the Magento\Catalog\Block\Adminhtml\Category\Widget\Chooser in my system.xml file for a field ?

The idea is to be able to pick a category from the chooser widget to store its id as a configuration field.

I don't want to use a simple text input as people will have to find the category id by themselves.

4
  • Or even a grid view with checkbox (like grid-serializer) can be life saver in such cases.
    – MagePsycho
    May 19, 2016 at 10:39
  • Are you able to manage this?
    – MagePsycho
    Apr 24, 2017 at 19:43
  • @MagePsycho nope still haven't found a way Apr 25, 2017 at 6:31
  • Renga I tried to use your solution but checkboxes are not coming. only tree is visible. I am using magento 2.3 Feb 6, 2019 at 17:51

1 Answer 1

5

To Creating A Multiple Category Chooser in Backend:

In your Widget.xml:

<parameter name="multi_category_chooser" xsi:type="block" visible="true" required="true" sort_order="10">
            <label translate="true">Select Categories</label>
            <block class="[Vendor]\[Modul]\Block\Adminhtml\Category\Widget\[Chooser]" />
        </parameter>

Create File : [Vendor][Modul]\Block\Adminhtml\Category\Widget[Chooser]

    <?php
namespace Vendor\Module\Block\Adminhtml\Category\Widget;

class Chooser extends \Magento\Backend\Block\Template {

    protected $_elementFactory;
    /**
     * @param \Magento\Backend\Block\Template\Context $context
     * @param \Magento\Framework\Data\Form\Element\Factory $elementFactory
     * @param array $data
     */
    public function __construct(
        \Magento\Backend\Block\Template\Context $context,
        \Magento\Framework\Data\Form\Element\Factory $elementFactory, array $data = []
    ) {
        $this->_elementFactory = $elementFactory;
        parent::__construct($context, $data);
    }

    /**
     * Prepare chooser element HTML
     *
     * @param \Magento\Framework\Data\Form\Element\AbstractElement $element Form Element
     * @return \Magento\Framework\Data\Form\Element\AbstractElement
     */
    public function prepareElementHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element) {
        $htmlId = $element->getId();
        $data = $element->getData();

        $data['after_element_js'] = $this->_afterElementJs($element);
        $data['after_element_html'] = $this->_afterElementHtml($element);
        $data['readonly'] = 'readonly';
        $htmlItem = $this->_elementFactory->create('text', ['data' => $data]);
        $htmlItem
                ->setId("{$htmlId}")
                ->setForm($element->getForm())
                ->addClass('required-entry')
                ->addClass('entities');
        $return = <<<HTML
                <div id="{$htmlId}-container" class="chooser_container">{$htmlItem->getElementHtml()}</div>
HTML;
        $element->setData('after_element_html', $return);
        return $element;
    }

    protected function _afterElementHtml($element)
    {
        $htmlId = $element->getId();
        $return = <<<HTML
            <a href="javascript:void(0)" onclick="MultiCategoryChooser.displayChooser('{$htmlId}-container')" class="widget-option-chooser" title="{__('Open Chooser')}">
                <img src="{$this->getViewFileUrl('images/rule_chooser_trigger.gif')}" alt="{__('Open Chooser')}" />
            </a>
            <a href="javascript:void(0)" onclick="MultiCategoryChooser.hideChooser('{$htmlId}-container')" title="{__('Apply')}">
                <img src="{$this->getViewFileUrl('images/rule_component_apply.gif')}" alt="{__('Apply')}">
            </a>
            <div class="chooser"></div>
HTML;
        return $return;
    }

    protected function _afterElementJs($element)
    {
        $chooserUrl = $this->getUrl('adminhtml/widget_instance/categories', []);
        $htmlId     = $element->getId();
        $return = <<<HTML
            <script>
                    require([
                    'jquery',
                    'Magento_Ui/js/modal/alert',
                    "prototype"
                ], function (jQuery, alert) {
                    var MultiCategoryChooser = {
                        displayChooser : function(chooser) {
                                chooser  = $(chooser).down('div.chooser');
                                entities = chooser.up('div.chooser_container').down('input[type="text"].entities').value;
                                postParameters = {selected: entities};
                                url = '{$chooserUrl}';

                                if (chooser && url) {
                                if (chooser.innerHTML == '') {
                                        new Ajax.Request(url, {
                                        method  : 'post',
                                        parameters : postParameters,
                                        onSuccess  : function(transport) {
                                                try {
                                                if (transport.responseText) {
                                                    Element.insert(chooser, transport.responseText);
                                                    chooser.removeClassName('no-display');
                                                    chooser.show();
                                                }
                                                } catch (e) {
                                                alert({
                                                   content: 'Error occurs during loading chooser.'
                                                });
                                                }
                                        }
                                    });
                                } else {
                                    chooser.removeClassName('no-display');
                                    chooser.show();
                                }
                                }
                       },
                        hideChooser : function(chooser) {
                                chooser = $(chooser).down('div.chooser');
                                if (chooser) {
                                chooser.addClassName('no-display');
                                chooser.hide();
                                }
                        },
                        checkCategory : function(event) {
                                node    = event.memo.node;
                                container = event.target.up('div.chooser_container');
                                value   = container.down('input[type="text"].entities').value.strip();
                                if (node.attributes.checked) {
                                if (value) ids = value.split(',');
                                else ids = [];
                                if (-1 == ids.indexOf(node.id)) {
                                    ids.push(node.id);
                                    container.down('input[type="text"].entities').value = ids.join(',');
                                }
                                } else {
                                ids = value.split(',');
                                while (-1 != ids.indexOf(node.id)) {
                                    ids.splice(ids.indexOf(node.id), 1);
                                    container.down('input[type="text"].entities').value = ids.join(',');
                                }
                                }
                        }
                      }
                    window.MultiCategoryChooser = MultiCategoryChooser;
                    jQuery(function() {
                        var container = $('{$htmlId}-container');
                        if (container) {
                            container.up(0).down('.control-value').hide();
                        }

                        Event.observe(document, 'node:changed', function(event){
                            MultiCategoryChooser.checkCategory(event);
                        });
                        Event.observe(document, 'category:beforeLoad', function(event) {
                                container = event.target.up('div.chooser_container');
                                value   = container.down('input[type="text"].entities').value.strip();
                            event.memo.treeLoader.baseParams.selected = value;
                        });
                    });
                });
            </script>
HTML;
        return $return;
    }
}

This is the Multi Category Chooser. enter image description here

5
  • I need same but your code is not working Jun 20, 2018 at 12:53
  • Ok, where you struggled Give more info otherwise I'm helpless. Because it's successfully working for me.
    – Renga
    Jun 22, 2018 at 7:45
  • Thanks for reply I want to add category chooser in my custom module can you please tell me the code where I ad and get proper category chooser Jun 22, 2018 at 12:20
  • Can I use this in custom admin form without ui component? Mar 22, 2019 at 9:21
  • I am getting this error: doesn't extend \Magento\Framework\Data\Form\Element\AbstractElement Mar 22, 2019 at 11:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.