4

I'm extending a Magento 2 module which doesn't use UI. I've added a new column for a custom attribute to the module's Admin grid. However, I'm trying to change the attribute to a multiselect, and I can't find a way to support multiselect without UI.

Here is what I have now:

<?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>
        <referenceBlock name="adminhtml.locator.grid.columnSet">
            <block class="Magento\Backend\Block\Widget\Grid\Column" as="brand" before="status">
                <arguments>
                    <argument name="header" xsi:type="string" translate="true">Brand</argument>
                    <argument name="index" xsi:type="string">brand</argument>
                    <argument name="header_css_class" xsi:type="string">col-brand</argument>
                    <argument name="column_css_class" xsi:type="string">col-brand</argument>
                    <argument name="type" xsi:type="string">options</argument>
                    <argument name="options" xsi:type="options" model="Mycompany\StoreLocator\Source\Brand\Options"/>
                </arguments>
            </block>
        </referenceBlock>
    </body>
</page>

This works great so long as I don't use a select attribute, but it breaks with a multiselect attribute. Filtering is also broken for this attribute once it has a comma in the attribute value.

Is there any way to support this without converting the whole form to UI?

2 Answers 2

2

I ended up adding a new filter and a new renderer for multiselect.

Updated layout 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>
        <referenceBlock name="adminhtml.locator.grid.columnSet">
            <block class="Magento\Backend\Block\Widget\Grid\Column" as="brand" before="status">
                <arguments>
                    <argument name="header" xsi:type="string" translate="true">Brand</argument>
                    <argument name="index" xsi:type="string">brand</argument>
                    <argument name="header_css_class" xsi:type="string">col-brand</argument>
                    <argument name="column_css_class" xsi:type="string">col-brand</argument>
                    <argument name="type" xsi:type="string">options</argument>
                    <argument name="options" xsi:type="options" model="Mycompany\StoreLocator\Source\GgBrand\Options"/>
                    <!-- start new -->
                    <argument name="filter" xsi:type="string">Mycompany\StoreLocator\Block\Backend\Widget\Grid\Column\Filter\Multiselect</argument>
                    <argument name="renderer" xsi:type="string">Mycompany\StoreLocator\Block\Backend\Widget\Grid\Column\Renderer\Multiselect</argument>
                    <!-- end new -->
                </arguments>
            </block>
        </referenceBlock>
    </body>
</page>

New file: Mycompany\StoreLocator\Block\Backend\Widget\Grid\Column\Filter\Multiselect.php

<?php

namespace Mycompany\StoreLocator\Block\Backend\Widget\Grid\Column\Filter;

class Multiselect extends \Magento\Backend\Block\Widget\Grid\Column\Filter\Select {
    /**
     * @return array|null
     */
    public function getCondition() {
        if ($this->getValue() === null) {
            return null;
        }

        $conditions = [];
        $values = explode(',', $this->getValue());
        foreach ($values as $value) {
            $conditions[] = ['finset' => $value];
        }

        return $conditions;
    }
}

New file: Mycompany\StoreLocator\Block\Backend\Widget\Grid\Column\Renderer\Multiselect.php

<?php

namespace Mycompany\StoreLocator\Block\Backend\Widget\Grid\Column\Renderer;

use Magento\Framework\DataObject;

class Multiselect extends \Magento\Backend\Block\Widget\Grid\Column\Renderer\AbstractRenderer
{
    /**
     * @param DataObject $row
     *
     * @return string
     */
    public function render(DataObject $row)
    {
        $labels = [];
        $values = explode(',', $this->_getValue($row));
        foreach ($values as $value) {
            $labels[] = MyAttributeTextLookupFunction($value);
        }

        $renderedValue = implode(', ', $labels);

        if ($this->getColumn()->getEditable()) {
            $result = '<div class="admin__grid-control">';
            $result .= $this->getColumn()->getEditOnly() ? ''
                : '<span class="admin__grid-control-value">' . $renderedValue . '</span>';

            return $result . $this->_getInputValueElement($row) . '</div>' ;
        }
        return $renderedValue;
    }
}

Then I just replaced MyAttributeTextLookupFunction() with my own code to get the attribute text that I needed for my custom attribute/column.

1
  • Thanks for the filter solution Sep 20, 2021 at 6:20
0

@Tyler thank you, your solution work fine, I add my rendered if someone need to add magento category as column in newsletter

<?php namespace CustomModule\Newsletter\Block\Backend\Widget\Grid\Column\Renderer;

use Magento\Framework\DataObject;

class Multiselect extends
\Magento\Backend\Block\Widget\Grid\Column\Renderer\AbstractRenderer
{

public $categoryList;

public function __construct(
    \Magento\Backend\Block\Context $context,
    \CustomModule\Newsletter\Model\Config\Source\Category $categoryList,
    array $data = []
)
{
    $this->categoryList = $categoryList->toOptionArray();
    parent::__construct($context, $data);
}

/**
 * @param DataObject $row
 *
 * @return string
 */
public function render(DataObject $row)
{
    $labels = [];
    $values = explode(',', $this->_getValue($row));
    foreach ($values as $value) {
        $labels[] = $this->getLabel($value);
    }

    $renderedValue = implode(', ', $labels);

    if ($this->getColumn()->getEditable()) {
        $result = '<div class="admin__grid-control">';
        $result .= $this->getColumn()->getEditOnly() ? ''
            : '<span class="admin__grid-control-value">' . $renderedValue . '</span>';

        return $result . $this->_getInputValueElement($row) . '</div>';
    }
    return $renderedValue;
}

public function getLabel($value)
{
    foreach ($this->categoryList as $category) {
        if ($category['value'] == $value) {
            return $category['label'];
        }
    }
}
}

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.