Question

Is there a way to make some listing select in filter to depend on some other select? I have seen this done on frontend checkout but that's a form not a list.

The idea is to make two columns searchable by select values but second select values are filtered by first option's value.

I tried something like this (similar to checkout implementation) but it does not work.

<column name="customer_id">
    <argument name="data" xsi:type="array">
        <item name="options" xsi:type="object">Module\Module\Model\Config\Source\Customers</item>
        <item name="config" xsi:type="array">
            <item name="filter" xsi:type="string">select</item>
            <item name="label" xsi:type="string" translate="true">Customer</item>
            <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/select</item>
            <item name="dataType" xsi:type="string">select</item>
            <item name="dataScope" xsi:type="string">customer</item>
            <item name="sortOrder" xsi:type="number">75</item>
            <item name="sortable" xsi:type="boolean">false</item>
        </item>
    </argument>
</column>

<column name="address_id">
    <argument name="data" xsi:type="array">
        <item name="options" xsi:type="object">Module\Module\Model\Config\Source\Address</item>
        <item name="config" xsi:type="array">
            <item name="filter" xsi:type="string">select</item>
            <item name="label" xsi:type="string" translate="true">Address</item>
            <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/select</item>
            <item name="dataType" xsi:type="string">select</item>
            <item name="dataScope" xsi:type="string">address_id</item>
            <item name="sortOrder" xsi:type="number">75</item>
            <item name="sortable" xsi:type="boolean">false</item>
            <item name="filterBy" xsi:type="array">
                <item name="target" xsi:type="string">${ $.provider }:${ $.parentScope }.customer_id</item>
                <item name="field" xsi:type="string">customer_id</item>
            </item>
        </item>
    </argument>
</column>
Was it helpful?

Solution

Feels like hacky solution but it works:

Ui component listing:

<filters name="listing_filters">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="columnsProvider" xsi:type="string">grid_listing.grid_listing.grids_columns</item>
                <item name="storageConfig" xsi:type="array">
                    <item name="provider" xsi:type="string">grid_listing.grid_listing.listing_top.bookmarks</item>
                    <item name="namespace" xsi:type="string">current.filters</item>
                </item>
                <item name="templates" xsi:type="array">
                    <item name="filters" xsi:type="array">
                        <item name="select" xsi:type="array">
                            <item name="component" xsi:type="string">Magento_Ui/js/form/element/select-custom</item>
                            <item name="template" xsi:type="string">ui/grid/filters/elements/select-custom</item>
                        </item>
                    </item>
                </item>
                <item name="childDefaults" xsi:type="array">
                    <item name="provider" xsi:type="string">grid_listing.grid_listing.listing_top.listing_filters</item>
                    <item name="imports" xsi:type="array">
                        <item name="visible" xsi:type="string">grid_listing.grid_listing.grid_columns.${ $.index }:visible</item>
                    </item>
                </item>
            </item>
            <item name="observers" xsi:type="array">
                <item name="column" xsi:type="string">column</item>
            </item>
        </argument>
    <filterSelect name="address_id" provider="${ $.parentName }">
        <settings>
            <options class="Vendor\Module\Model\Config\Source\Address"/>
            <label translate="true">Address</label>
            <dataScope>address_id</dataScope>
            <imports>
                <link name="visible">ns = ${ $.ns }, componentType = column, index = ${ $.index }:visible</link>
            </imports>
        </settings>
    </filterSelect>
    <filterSelect name="customer_id" provider="${ $.parentName }">
        <settings>
            <options class="Vendor\Module\Model\Config\Source\Customers"/>
            <label translate="true">Customer</label>
            <dataScope>customer_id</dataScope>
            <imports>
                <link name="visible">ns = ${ $.ns }, componentType = column, index = ${ $.index }:visible</link>
            </imports>
        </settings>
    </filterSelect>
</filters>

js:

define([
    'Magento_Ui/js/form/element/select',
    'jquery',
    'uiRegistry',
    'mage/url'
], function (Select, $, uiRegistry, url) {
    'use strict';

    function parseOptions(nodes, captionValue) {
        var caption,
            value;

        nodes = _.map(nodes, function (node) {
            value = node.value;

            if (value === null || value === captionValue) {
                if (_.isUndefined(caption)) {
                    caption = node.label;
                }
            } else {
                return node;
            }
        });

        return {
            options: _.compact(nodes),
            caption: _.isString(caption) ? caption : false
        };
    }

    function findFirst(data) {
        var value;

        data.some(function (node) {
            value = node.value;

            if (Array.isArray(value)) {
                value = findFirst(value);
            }

            return !_.isUndefined(value);
        });

        return value;
    }

    function indexOptions(data, result) {
        var value;

        result = result || {};

        data.forEach(function (item) {
            value = item.value;

            if (Array.isArray(value)) {
                indexOptions(value, result);
            } else {
                result[value] = item;
            }
        });

        return result;
    }

    return Select.extend({

        initialize: function () {
            self = this;
            this._super();

            if (this.customEntry) {
                registry.get(this.name, this.initInput.bind(this));
            }

            if (this.filterBy) {
                this.initFilter();
            }

            // filter and update address select

            if (this.inputName == 'address_id' && this.source.filters.customer_id !== undefined) {

                this.filterBy = {
                    field: 'customer_id',
                    target: 'customer_id'
                }

                this.customerFilter(this.source.filters.customer_id, 'customer_id');
            }

            return this;
        },

        customerFilter: function (value, field) {
            var source = this.initialOptions,
                result;

            result = _.filter(source, function (item) {
                return item[field] === value || item.value === '';
            });

            this.setOptions(result);
        },

        onUpdate: function () {
            var self = this;

            this.bubble('update', this.hasChanged());

            this.validate();

            // filter and update address select

            if (this.inputName == 'customer_id') {

                var address = uiRegistry.get(this.parentName + '.' + 'address_id'),
                    options = address.indexedOptions,
                    source = address.initialOptions,
                    result;

                result = _.filter(source, function (item) {
                    return item[self.inputName] === self.value();
                });

                address.setOptions(result);
            }
        }
    });
});
Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top