Perspective table header filter dropdowns - matching column widths

I am now using this filter.
This will filter according to chosen 'Country'

But what if I want to show all Countries? (say value.dropdown ="")

How do I do that?

One simple option is to add an extra condition outside the filter function that acts as a short circuit. E.g:

anyCountry = # some property reference + some logic that returns a boolean 
return filter(lambda row: anyCountry or row['Country'] == value.dropdown, value.data)
2 Likes

Iā€™d keep the filter the same, but skip it entirely if any_country is true.

if any_country:
    return value.data
else:
    return filter(lambda row: row['Country'] == value.dropdown, value.data)

edit: Actually, reading the older posts, it seems you have more than one filter, in which case it's probably simpler to change the lambda like Paul did.

For one of my previous projects, I had to dev a page that showed a whole bunch of data depending on a whole bunch of filters, which were dynamic and of different types.

The way I did this, to keep it as simple as possible, was to first process the filters to only keep those that had a selection. So the dropdowns where nothing was selected weren't used at all, same for multi-state buttons, text fields, etc. that still had their default values.
The filter processing resulted in a list of filters, that I could then use on my data.

The transform on the data then used a function that took a filter and the data, and returned a boolean indicating if the data should stay or be discarded. Something like this:

filtered_data = filter(
    lambda item: all(check_filter(item, f) for f in filters),
    data
)

The check_filter function is responsible for letting items pass, and the lambda in the filter function only checks that all filters were OK.

This may be overkill if you only have 2 filters, but now you have in the answers to this thread both a very simple filtering system AND one that can handle very complex cases. It's up to you to find the proper middle ground for your use case.

edit 2:
Just in case, here's what the processed filters might look like (actual example from the actual page):

[
  {
    "type": "bool",
    "value": false,
    "field_name": "instance_k7_interdit"
  },
  {
    "type": "list",
    "value": [
      "ALPINAL"
    ],
    "field_name": "template_profile_be"
  },
  {
    "type": "strict",
    "value": 3,
    "field_name": "template_id"
  }
]

The field_name is used to know what column the filter applies on.

And the check_filter function used in the filter:

	def check_filter(item, f):
		item = item.get(f.field_name)
		if f.get('type') == 'date':
			start_ok = f.value['start_date'] is None or item >= system.date.toMillis(f.value['start_date'])
			end_ok = f.value['end_date'] is None or item <= system.date.toMillis(f.value['end_date'])
			return start_ok and end_ok
		elif f.get('type') == 'bool':
			return item == f.value
		elif f.get('type') in {'list', 'group'} or isinstance(f.value, ArrayList):
			return any(str(item) == str(elem) for elem in f.value)
		elif f.get('type') == 'strict':
			return str(item) == str(f.value)
		else:
			return str(f.value) in str(item)

I realize now that the date conversion to milli second should probably be done in an earlier step...

Well you'd be amaze, I only did use one line of code to filter multiple columns. :slight_smile:

Created a dictionary where name of key === name of column
image

On dropdown value changed.
if Null means select all. Assign all options to it.

def valueChanged(self, previousValue, currentValue, origin, missedEvents):
	if currentValue.value is None:
		val = [x.value for x in self.props.options]
	else:
		val = currentValue.value
		
	self.view.custom.tableFilters.department = val

On Table Data Binding:
On filter Lambda statement, I use in, that is row['country'] in value.dropdown

p.s.
Credit to @pascal.fragnoud for the filter lambda code.

Well played !

The pythonic way of writing this lambda would be:

lambda row: all(row[name] in options for name, options in filterObjects.iteritems()))

.iteritems() will generate tuples containing the key and the value of the items,
and you can remove the brackets [] because you don't need to generate a list: all can take a generator.

1 Like