xaksis / vue-good-table

An easy to use powerful data table for vuejs with advanced customizations including sorting, column filtering, pagination, grouping etc
https://xaksis.github.io/vue-good-table/
MIT License
2.16k stars 405 forks source link

Column filter ignores empty string #476

Open jcasale opened 5 years ago

jcasale commented 5 years ago

Issue Type

Specs

2.16.0

Google Chrome version 71.0.3578.98 (Official Build) (64-bit)

Expected Behavior

After creating a filter selection based on an empty string, I can filter all rows with values.

Actual Behavior

With the filter selection with the empty string enabled, the resulting query string for remote mode lacks the filter.

Steps to Reproduce the Problem

  1. Add a filter selection to a row with an entry such as [{ value: "", text: "empty" }]
  2. Enable the filter
  3. Analyze the resulting query string

Possibly related to #383

ow-en commented 5 years ago

Please provide a fiddle that reproduces the issue, or something close to it. Your description is a little vague.

If I'm understanding this correctly, you're looking to filter out all rows where row.value is equal or not equal to an empty string? (Essentially a null check)

You also referenced #383, but I'm not seeing how that ties in here. 383 deals with the filterValue property, which pre-populates a row's filter value.

If that is all you are trying to do here, unfortunately, setting filterValue to an empty string is not going to produce the functionality you're describing.

Were this a client-side table, I would recommend a FilterFn, listed in the docs.

In remote mode, it's more difficult for me to recommend a solution, because all of the filter logic is subject to your own back-end setup. Generally, the type of logic you're describing would need to take place on the server.

After the server receives your serverParams object, you would need to have your own logic in place that reads that object, the columnFilters > row > query, and then returns X rows based on the value received (empty string/null or not).

jcasale commented 5 years ago

Hi, The desire was to be able to filter and include only values for a given column which where empty (exclude any row that have a value in that column). While building the repro I found the problem which introduced the ambiguity in the project I am working with.

It turns out that when you set the filter options on a column as follows:

filterOptions: {
  enabled: true,
  placeholder: " ",
  trigger: "enter"
}

pressing enter implements a filter with a value set to the empty string, so the actual functionality exists.

However, the nuance here is how to remove that filter without refreshing the browser? Even if you clear an existing filter (delete a value and press enter), the resulting filter is now defined with an empty string which makes the resulting behavior unpredictable.

How have other approached this scenario to your knowledge?

ow-en commented 5 years ago

Hi @jcasale , thanks for your response.

So the actual issue is clearing the filter value, not the implementation of the filter itself?

As you noted, applying a placeholder of " " and triggering that filter applies a filter value, though the filter value isn't of an empty string, it's of a string containing whitespace.

Based on the functionality you described, I'm still going to say that this is something that needs to be handled in your server-side logic (assuming this is a remote-mode table, which I believe you mentioned). Were this a client-side table, a filterFn would work fine.

In your server-side logic, you would need to receive the serverParams object from the client, and run a check on the column you're trying to implement this functionality in. Something to the effect of (pseudocode):

if (serverParams.columnFilters.columnName.value == null || "" || string.isNullOrEmpty {
return rows where !rows.columnName.value
}

Now, regarding resetting column filter values to blank after application of a filter, simply deleting all value from the filter input should work.

If for some reason deleting the input contents does not reset the serverParams -> columnFilters value, a reset button or function would do the trick. You could add reset logic to your @on-filter-change, as well.

An example of a reset function that fully resets the serverParams object (including columnFilters and values), as well as everything else, see #486.

Again, it's difficult for me to fully advise on this because it's a remote-mode table, but I think the above should clarify some of that. If you are still encountering the issue after trying all of the above, please make a fiddle that reproduces the filter problem.

I'm able to successfully clear the filter values upon delete of the input's contents, so if you are able to reproduce that issue, I'd be happy to look into it further.

jcasale commented 5 years ago

See this fiddle, the placeholder is irrelevant. On line 37, I have it commented out, however when you type a value and press enter, you see the following object at the console:

{
  columnFilters: {
    description: "foo"
  }
}

After clearing the value and pressing enter, the following object is sent to the console:

{
  columnFilters: {
    description: ""
  }
}

Note that description is an empty string, not a space like the placeholder was.

In normal cases, as a user operates the grid and accumulates cleared filters, we can skip those when updating the request parameters and everything works fine. My case is unique in that when you hit enter on a blank filter, I want that empty string. However, I will need to implement a reset button to undo this when you no longer want to filter on rows which do not have a value for that column.

The unintuitive part will end up being that you can no longer "clear" a single filter as that implements the filter I just described if I were to leverage the empty string case.

Does a solution exist where I can style the filter field so I can offer an individual reset button and then what should I manipulate to only modify the filter for a single column? If I understand #486 there is no way to manipulate the stored column filters?

Thanks for all the help.

ow-en commented 5 years ago

@jcasale After reading through your response, I have some ideas that I think will help you. It's late here, but I'll write up some options tomorrow, and we can go from there.

ow-en commented 5 years ago

Okay @jcasale , a few thoughts: I looked at your fiddle, and I think I more or less understand what you're trying to achieve. First, if you're having problems resetting the columnFilters object, adding a segment to onColumnFilter like the below may help you out:

    onColumnFilter(params) {
      if (params.columnFilters.description == "") // or whatever condition {
        params.columnFilters.description = " " // reset the placeholder
      }
      this.updateParams(params);
      this.loadItems();
    },

Essentially, if you clear the column and press enter, the above successfully force-resets the value back to your placeholder (" "), or any value you choose. That, or something similar, should cover your question regarding modifying the filter for a single column. The reset functionality outlined in #486 is a table-wide reset function. It will return placeholder values, but it will do so table-wide. If you're looking to return only a single column back to its original state, adding a conditional like I outlined above to onColumnFilter or loadItems would likely be the way to go.

Regarding capturing the empty string to use as a filter value, again, this would come back to your server-side logic. Your server would need to catch that value, and returns row based on the condition (in this case being !row.description vs row.description).

Using the blank value as a filter queue, however, is not ideal (in my opinion). I would recommend considering using a separate denotation on that column to return rows with/without descriptions.

Two ideas come to mind:

1) Change the filter to a dropdown with two options: "description" and "none." Then, in your server-side logic, you would setup a catcher to return records with description, vs records without description, based on the value received.

2) If you need to retain the filter input, in order to filter by user-input or otherwise, you could set up a keyword or value as a flag. The dropdown would be better here, because it would require less user education, but both would work. If a keyword were set up, again, in your server-side logic, you would returns rows based on the existence/nonexistence of that keyword. Otherwise, return rows based on the filter input value as normal.

However you choose to proceed, this still appears to me to be an issue with server-side logic. Running the table in remote mode is inherently heavily dependent on the your personal configuration on the server. Modification of your existing filter logic is likely the best way to go. I would also strongly recommend considering using a different flag to return records with/without description (or x value). Using the blank input as the modifier seems like it might be unintuitive from a UX standpoint, and likely wasn't considered or planned for when designing the plugin's functionality.

All of the above are just briefly thought out ideas that may help you find a solution. I'll keep thinking about this in the coming days, and if I can think of another way to solve your problem, I'll definitely let you know.