Magento 2 Column search dependency in UI listing
-
23-02-2021 - |
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>
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