Skip to content

Improvement: Fire <b-table> filtered-event when filteredItems array gets modified #1989

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ddweber opened this issue Aug 7, 2018 · 3 comments · Fixed by #2149
Closed

Improvement: Fire <b-table> filtered-event when filteredItems array gets modified #1989

ddweber opened this issue Aug 7, 2018 · 3 comments · Fixed by #2149

Comments

@ddweber
Copy link

ddweber commented Aug 7, 2018

In the current state of the b-table component the filtered event only gets fired when the length of the filteredItems array changes.
But there may be use cases when the length of the array does not change, but the array items itself have changed/ have been modified.
In my particular case i am implementing a dynamic scrolling for the table where data is fetched/loaded blockwise and pushed in rather then spliced out the items array, so that the count does not change at all.

My suggestion: Would it be possible to change the watcher for the filteredItems array to watch for array mutation instead of array length? Or are there any side effect (performance issues) that i did not think of?

Original:

filteredItems (newVal, oldVal) {
      if (this.localFiltering && newVal.length !== oldVal.length) {
        // Emit a filtered notification event, as number of filtered items has changed
        this.$emit('filtered', newVal)
      }

Improved:

filteredItems (newVal) {
      if (this.localFiltering) {
        // Emit a filtered notification event, as filteredItems array has changed
        this.$emit('filtered', newVal)
      }
@tmorehouse
Copy link
Member

Each time the table is altered (even if not filtered), the filteredItems is updated (i.e. a new slice is created, creating a new table reference).

One would need to do a deep (or possibly a shallow) comparison of the previous contents of filteredItems vs the new Contents of finteredItems. There is a utility method in BootstrapVue that can do this type of comparison (it is used for comparing form-select, form-radios, form-checkboxes.

It could be used here as well.

@ddweber
Copy link
Author

ddweber commented Aug 8, 2018

Ok, thanks for the explanation :)
But how would that comparison be possbile when Vue is only keeping a reference of the filteredItems array like stated in the Vue API documentation of the watch method?

vue-watch

@tmorehouse
Copy link
Member

During the process that computes the items (which could be driven by a provider), the filter process runs, and a new reference to a filtered array is created and stored in this.filteredItems (basically via Array.slice(...)). This creates a new array (rather than updating the contents of the array).

So even if the filtered items remain the same (say after a local pagination). which means that with your suggested code change, the filtered event would fire every single time the table is paginated or sorted, basically emitting false filtered triggers.

A shallow/deep comparison of newVal and oldVal is required (i.e. the looseEquals comparison).

import looseEquals from ../utils
let a = [1, 2, 3, 4]
let b = [1, 2, 3, 4]
a === b //  = false, because a and b are different array references
looseEquals(a, b) // = true, because "contents" of a and b are the same

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment