reactable
reactable copied to clipboard
Include more examples of filterMethod in the documentation (multi-value filter, numeric range filter, date range filter)
reactable
is really great. One minor thing that I feel could be improved in the documentation are some additional examples of the basic custom filtering. Below are examples of multi-value filter
, numeric range filter
and date range filter
. I know these things may seem obvious to someone JavaScript literate, but some R folks may find them useful.
library(reactable)
data <- data.frame(
letters = letters[1:24],
decimals = round(runif(24), 2),
dates = c(as.Date("2022-12-31") + 1:24)
)
reactable(
data,
columns = list(
letters = colDef(
filterable = TRUE,
# filtering for multiple values using regex partial match
# a|b|c to get a, b and c
# ^a$|b to get exact match for a and partial match for b
filterMethod = JS("function(rows, columnId, filterValue) {
const pattern = new RegExp(filterValue, 'i')
return rows.filter(function(row) {
return pattern.test(row.values[columnId])
})
}")
),
decimals = colDef(
filterable = TRUE,
# Filter by a single number (greater than or equal to)
# 0.4 filters value greater than or equal to 0.4
# filter by a range
# 0.4 0.5 filters values between 0.4 and 0.5 (inclusive)
filterMethod = JS("function(rows, columnId, filterValue) {
var range = filterValue.split(' ');
range[0] = Number(range[0]) || -Infinity;
range[1] = Number(range[1]) || Infinity;
return rows.filter(function(row) {
return row.values[columnId] >= range[0] &&
row.values[columnId] <= range[1]
})
}")
),
dates = colDef(
filterable = TRUE,
# string filtering for dates
# 2023-01-02 for dates 2023-01-02 or later
# 2023-01-02 2023-01-03 for dates between 2023-01-02 and 2023-01-03 (inclusive)
# beware that if only one date provided, dates are filtered using the date to
# of 9999-12-31 (this date can be changed in the JavaScript code)
filterMethod = JS("function(rows, columnId, filterValue) {
var test = filterValue.split(' ');
test[1] = test[1] || '9999-12-31';
return rows.filter(function(row) {
return row.values[columnId] >= test[0] &&
row.values[columnId] <= test[1]
})
}")
)
),
defaultPageSize = 5
)
The numeric range filter was asked in #9 . I am well aware the implementation above is far from ideal though.
Agreed, and thanks for the suggestions. The only thing preventing me from adding more complex examples like this are that they're rough to use when you just have a free-form text box. Ideally, these would come with a multi-select input, dual range slider, and date picker input, but those are also complicated examples to create, and I haven't had the time. Some of these may so useful that they're worth documenting without a corresponding input though.
Hey guys, Maybe someone could integrate noUiSlider into provided decimals example? I would do it myself, but I don't know javascript at all :(
I have a closely related question. I have a table with dropdown select filters for some columns, based on this example. This seems to match rows based on a regular expression match, and does not match exact values. For instance, when "transition", "conflict", and "transition & conflict" are possible values, selecting the "conflict" option, this will filter both "conflict" and "transition & conflict". Is there a way to make this match only to exact values. I assume that it requires a custom filterMethod function, but I'm not JS literate, and have not found an example to adapt in the Reactable documentation.
@timothoms you are right. A custom filterMethod
should accomplish what you want. You can try something along these lines to make this match only to exact values:
function filterRows(rows, columnId, filterValue) {
return rows.filter(function(row) {
return row.values[columnId] === filterValue;
});
}
Here is a very simple runnable example:
library(htmltools)
data <- data.frame(
col1 = c("transition", "conflict", "transition & conflict")
)
reactable(
data,
filterable = TRUE,
columns = list(
col1 = colDef(
filterMethod = JS("function(rows, columnId, filterValue) {
return rows.filter(function(row) {
return row.values[columnId] === filterValue;
})
}"),
filterInput = function(values, name) {
tags$select(
# Set to undefined to clear the filter
onchange = sprintf("Reactable.setFilter('cars-select', '%s', event.target.value || undefined)", name),
# "All" has an empty value to clear the filter, and is the default option
tags$option(value = "", "All"),
lapply(unique(values), tags$option),
"aria-label" = sprintf("Filter %s", name),
style = "width: 100%; height: 28px;"
)
}
)
),
defaultPageSize = 5,
elementId = "cars-select"
)
Thank you very much! That is so simple, now I feel silly to have asked.