skip to Main Content

I am using reactable with custom filtering/searching methods and regular expression patterns, and special functions to collapse rows if they are identical (to avoid repetition of the same rows, which can occur in my database). See a reproducible example below:

library(reactable)
library(htmltools)

customsearch <-  JS('
function(rows, columnIds, filterValue) {
    let arrFilterValues = filterValue.split(" ");

    return rows.filter(function(row) {
        return arrFilterValues.map(function(e) {
            return columnIds.some(function(columnId) {
                return new RegExp(e,"i").test(row.values[columnId])
            });
        }).every(v => v === true);
    });
}')

customfilter <- JS('function(rows, columnId, filterValue) {
    let arrFilterValues = filterValue.split(" ");

    return rows.filter(function(row) {
        return arrFilterValues.map(function(e) {
                return new RegExp(e,"i").test(row.values[columnId])
        }).every(v => v === true);
    });
}')


reactable(iris,filterable=TRUE,searchable=TRUE,static=TRUE, rowStyle=JS("function(rowInfo, state) {
    const firstSorted = state.sorted[0]
    if (!firstSorted || firstSorted.id === 'Petal.Length') {
      const prevRow = state.pageRows[rowInfo.viewIndex - 1]
      if (prevRow && rowInfo.values['Petal.Length'] === prevRow['Petal.Length']) {
        return { visibility: 'collapse' }
      }
    }
  }"), searchMethod = customsearch, defaultColDef=colDef(filterMethod=customfilter, html=TRUE))

The problem is that, if I input some characters in the search box, the table disappear and the only way to make it appear again is to refresh the page: I can put numbers or text in the search box, but as soon as I input "" (as well as other special characters I guess, such as "*") the table disappears. This also occur if I input a string which is not found in the table.

Is there a way to prevent this behavior?

2

Answers


  1. You could handle error if the proposed regex (a single ) is invalid, and return the whole table in that case ? I’m not a daily javascript user, more python/R and I also prefer to avoid regex as much as possible, so I may be missing other better approaches but this appears to work on basic test.

    replace the JS("") part with

    "function(rows, columnId, filterValue) {
                              try {
              const pattern = new RegExp(filterValue, 'i');
              return rows.filter(function(row) {
                return pattern.test(row.values[columnId]);
              });
            } catch (e) {
              // If regex creation fails, return all rows
              return rows;
            }
          }"
    
    Login or Signup to reply.
  2. The table disappears if the filtered result set has zero rows because in the rowStyle function you have a rowInfo.viewIndex and this is undefined if the filtered table has zero rows (in particular, rowInfo is undefined in this case). I added an extra condition inside the function which checks for this case, this should avoid the crash.

    Concerning the crash if the user inputs a special character the problem is that that in this case no regex for the search can be constructed. Below I implemented a solution where in such a situation I remove the last character from the filter value and return this result set (i.e., the last filtered result set is kept). There are also other possibilities, e.g. returning an empty table.

    library(reactable)
    library(htmltools)
    
    customsearch <-  JS('
    function(rows, columnIds, filterValue) {
        let arrFilterValues = filterValue.split(" ");
          return rows.filter(function(row) {
              return arrFilterValues.map(function(e) {
                  return columnIds.some(function(columnId) {
                      try {
                          return new RegExp(e,"i").test(row.values[columnId]);
                      } catch (err) {
                          return new RegExp(e.slice(0, -1), "i").test(row.values[columnId]);;
                      }
                  });
              }).every(v => v === true);
          });
    }')
    
    customfilter <- JS('function(rows, columnId, filterValue) {
        let arrFilterValues = filterValue.split(" ");
    
        return rows.filter(function(row) {
            return arrFilterValues.map(function(e) {
                try {
                    return new RegExp(e,"i").test(row.values[columnId]);
                } catch (err) {
                    return new RegExp(e.slice(0, -1), "i").test(row.values[columnId]);;
                }
            }).every(v => v === true);
        });
    }')
    
    reactable(iris,filterable=TRUE,searchable=TRUE,static=TRUE, rowStyle=JS("function(rowInfo, state) {
        const firstSorted = state.sorted[0]
        if ((!firstSorted || firstSorted.id === 'Petal.Length') && (rowInfo !== undefined)) {
          const prevRow = state.pageRows[rowInfo.viewIndex - 1]
          if (prevRow && rowInfo.values['Petal.Length'] === prevRow['Petal.Length']) {
            return { visibility: 'collapse' }
          }
        }
      }"), searchMethod = customsearch, defaultColDef=colDef(filterMethod=customfilter, html=TRUE))
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search