Skip to content

Custom transformations for array collections #213

Description

@player-03

As discussed in #209, there's a bunch of duplicate code in the hierarchical collection classes, a lot of it is related to filtering and sorting, and it bugs me. There's actually also some in ArrayCollection, but I didn't mention it there because the approach I was using wouldn't have worked.

Another thing that bugs me is the naming convention. _filterAndSortData, refreshFilterAndSort(), findItemInFilteredOrSortedBranch(), and so on. These are some very long names! They make the classes take somewhat longer to read just by sheer word count, not to mention the overhead of scrolling sideways to see the rest of a line.

Perhaps worst of all is what it implies would happen if you found a third transformation to apply. Let's say you wanted to be able to group similar items (the user would provide a function to define "similar"), like the browser console does if it gets 20 of the same error in a row. Would it now be _filterSortAndGroupData? findItemInFilteredSortedOrGroupedBranch()? I agree that grouping doesn't seem worth doing, but how sure are you that you'll never find a third transformation to do?

I'd like to propose a new concept, and a shorter name to go with it. You have source data (_array), and you have display data (previously _filterSortAndGroupData, now _displayData or similar). Called that because it's what gets presented to the user via get(), and it's what gets rendered in a ListView or TreeView. And it neatly matches the new descriptions of filtering and sorting.


As a brief aside, I recently found an unsupported use case. I want a TreeView that renders my data and includes an extra button at the end of each branch. Clicking the button (that is, selecting the ItemRenderer displaying "+") would create a new entry in that branch. The extra button would NOT appear in the source data, but the new entry would.

Looking at my options, I decided the easiest approach would be to copy all of ArrayHierarchicalCollection and add this custom feature there. Maybe I'd add a special case to get() if index == branchChildren.length, or something.

This is, of course, when I got sidetracked by the sheer amount of code and started posting PRs and issues, and began thinking about _filterAndSortData. What if, instead of messing with all the get-related functions, I could just modify this array? It's non-destructive, which is exactly what I want, and getLength() and get() will both just return its info. Others might be more complicated, but it's a start.

So that's my third operation. Filter, sort, append.


I don't want my use case added to Feathers, it's way too specific. Instead, I want to think about ways to support arbitrary non-destructive operations.

My proposal is to treat all these non-destructive operations as a pipeline. To create _displayArray, we start with a copy of _array and run all the operations on the copy, in order. Filter, sort, any user-defined operations. Once done, _displayArray will contain only what should be displayed.

Setting is tougher. A lot tougher, if #211 and #212 are any indication. But I think #211 would work well with the pipeline approach.

  1. Update the original value in _array (if any).
  2. Update or create the FilterAndSortItem.
  3. Run the pipeline. (I imagine I'd make it runnable on a single branch.)
  4. Check if the FilterAndSortItem is still there, and if there was an original value. Dispatch the appropriate event.

No more if else chains to handle the various filtered/unfiltered combos, inside another if else chain to handle filtering vs. sorting. No more getSortedInsertionIndex() function, actually, which I guess could be a performance hit. (If that's an issue, I have a plan to replace it.) No more accidentally forgetting a combination; everything gets applied every time.


Ok, I've been typing for hours now, I should stop here. That's the rough outline, details to follow.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions