You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is it. The big finale to FF's MVP: Type Filtering.
As the user scrolls around on the map, they would like to filter by one or more types. The types that are available to filter directly reflects the types that are currently visible on the map. This means that you can filter in cluster view or location view. It also means that you should GET /types.json each time the map scrolls, and provide the NE/SW lat/lng of the viewport as well; the API will handle giving you the types that have at least one location inside the viewport, as well as their respective counts.
Currently on fallingfruit.org, the website only supports filtering by at most one type. Our app will offer filtering by any number of types. Note that the backend already supports this by taking an array of types; it's just that the current website does not, because UI is tricky.
We have decided to solve this problem with a hierarchal tree select, using this library: react-dropdown-tree-select.
Additionally, types are represented in a hierarchal format. For now, Ethan has chosen to limit the depth of the hierarchy to 1, so assume that for now:
The API data gives this tree by specifying a parent_id for each type in GET /types/{id}.json. You will have to build this tree in order to show the hierarchy, because the tree select library expects data in the form of nested objects. (CS 225, anyone?)
Right now, it seems that rebuilding the tree after the map scrolls would be slow because parent_id is currently not included in GET /types.json, which means you'd have to GET /types/{id}.json for each type, which fallingfruit.org definitely does not do. @ezwelty, does the current app get the type hierarchy from somewhere? How would we do that as well? See bottom of issue for more details.
Another difference we'll have is the type counts. On fallingfruit.org, the count of the parent type is not the sum of the counts of the child types:
Notice how 0 != 2 + 12. It's this way because the count on the parent actually represents the number of locations that are categorized as just "Maple", and not a specific kind of maple. (Let's call them uncategorized maples.) When you click on it, however, it seems that the website does explicitly select the parent and its children (all maples). You'll see that the count also updates to the sum 14.
This is unintuitive, and will also not conceptually work with our tree select, since it's implied that clicking on the parent type will select all the child types. We've decided to solve this by moving the uncategorized maples to a child category "Other" under the general type Maple (see designs below). That "Other" will own the uncategorized count, and the parent type will then have the sum of its children's counts.
Filtering is implemented by sending an array of type IDs to the backend in requests such as GET /locations.json and GET /types.json. We currently have a React context called SearchContext that conveys the viewport of selected search results to MapPage, so it can pan to the searched location. You can take advantage of that context to sync the list of currently filtered type IDs to MapPage as well, so it can include those in its GET /locations.json requests.
We also use React context for sharing the current viewport of the map across components. That's in MapContext's view.
Searching for types
There are tons of types in FF, so it's critical that the user can search for them while filtering. Luckily, the library we're using provides searching built-in. Note these options:
keepTreeOnSearch: By default the tree gets flattened when you're searching, but we want the tree to stay.
Styling
Unlike Reach UI, the library we're using doesn't have as props to specify what components to use for checkboxes, inputs, etc. So we will likely have to replicate styles from our existing UI components, without being able to use the components themselves.
Make sure to reference react-dropdown-tree-select's styling tips, specifically the default class names so that you can select them while styling the outer component.
Relevant Figma designs
Mobile:
Desktop:
Suggested branch name: type-filtering
Suggested PR title (as would probably be suggested by @code-arman): <some relevant emoji> Add type filtering
Using React context to pass data around. We do this in order to avoid drilling props back and forth in a complicated component hierarchy. This one is pretty valuable, since some kind of structured state management is essential in larger apps. Don't worry, context is pretty easy to use, without a lot of boilerplate. (Remember how we said we wouldn't use Redux in our project? We're still not, but Redux is actually implemented with React contexts.)
Data structures and building a tree in JavaScript. Who would have thought?
Styling, styling, styling
Breaking a complex feature down into simple parts, and implementing each part cleanly
Todo
Since this is a big feature, let Jeffrey know about what he can help out on by sometime mid-week, if you think it's necessary
Adding a "pressed" prop to IconButton
Reorganizing the shared Search component that is currently in desktop and mobile to include the filter button and the tree select component. In that shared component, at most one of [search suggestions, type filtering] should be visible. Note that it's best to just wrap the existing Search component so it doesn't get too long
Building the tree with the type hierarchy into a format that the tree select will expect
In particular, ensuring that type counts are correct and adding the "Other" category to each parent type
Loading types data based on the current viewport of the map, from MapContext
Upon changes in the tree select, propagate the correct list of types to the map via SearchContext
Being careful with the "Other" category
Adding type search to the tree select
Style the tree select nodes
Style the tree select search input
Useful links
React context docs. Note that we'll probably never be using the Context.Consumer higher-order component, just useContext hooks anywhere we need it.
One simple solution is to multiple requests is to include parent_id in GET /types.json so we don't have to make additional GET requests for each type. Rebuilding the actual tree will probably be very fast compared to the overhead of making the network request, so this should work fine for now.
Another solution, which @ezwelty mentioned and requires a lot more work, is to change the API to only return type IDs throughout all requests, and expect the frontend to get all type information ahead of time. This may speed up the API a bit, but requires more investigation.
Virtualization
The library we're using now supports virtualization out of the box, which means that DOM elements are only rendered as they scroll into view. Definitely great to have.
The text was updated successfully, but these errors were encountered:
Description
This is it. The big finale to FF's MVP: Type Filtering.
As the user scrolls around on the map, they would like to filter by one or more types. The types that are available to filter directly reflects the types that are currently visible on the map. This means that you can filter in cluster view or location view. It also means that you should
GET /types.json
each time the map scrolls, and provide the NE/SW lat/lng of the viewport as well; the API will handle giving you the types that have at least one location inside the viewport, as well as their respective counts.Currently on fallingfruit.org, the website only supports filtering by at most one type. Our app will offer filtering by any number of types. Note that the backend already supports this by taking an array of types; it's just that the current website does not, because UI is tricky.
We have decided to solve this problem with a hierarchal tree select, using this library: react-dropdown-tree-select.
Additionally, types are represented in a hierarchal format. For now, Ethan has chosen to limit the depth of the hierarchy to 1, so assume that for now:
The API data gives this tree by specifying a
parent_id
for each type inGET /types/{id}.json
. You will have to build this tree in order to show the hierarchy, because the tree select library expects data in the form of nested objects. (CS 225, anyone?)Right now, it seems that rebuilding the tree after the map scrolls would be slow because
parent_id
is currently not included inGET /types.json
, which means you'd have toGET /types/{id}.json
for each type, which fallingfruit.org definitely does not do. @ezwelty, does the current app get the type hierarchy from somewhere? How would we do that as well? See bottom of issue for more details.Another difference we'll have is the type counts. On fallingfruit.org, the count of the parent type is not the sum of the counts of the child types:
Notice how
0 != 2 + 12
. It's this way because the count on the parent actually represents the number of locations that are categorized as just "Maple", and not a specific kind of maple. (Let's call them uncategorized maples.) When you click on it, however, it seems that the website does explicitly select the parent and its children (all maples). You'll see that the count also updates to the sum 14.This is unintuitive, and will also not conceptually work with our tree select, since it's implied that clicking on the parent type will select all the child types. We've decided to solve this by moving the uncategorized maples to a child category "Other" under the general type Maple (see designs below). That "Other" will own the uncategorized count, and the parent type will then have the sum of its children's counts.
Filtering is implemented by sending an array of type IDs to the backend in requests such as
GET /locations.json
andGET /types.json
. We currently have a React context calledSearchContext
that conveys the viewport of selected search results toMapPage
, so it can pan to the searched location. You can take advantage of that context to sync the list of currently filtered type IDs toMapPage
as well, so it can include those in itsGET /locations.json
requests.We also use React context for sharing the current viewport of the map across components. That's in
MapContext
'sview
.Searching for types
There are tons of types in FF, so it's critical that the user can search for them while filtering. Luckily, the library we're using provides searching built-in. Note these options:
keepTreeOnSearch: By default the tree gets flattened when you're searching, but we want the tree to stay.
Styling
Unlike Reach UI, the library we're using doesn't have
as
props to specify what components to use for checkboxes, inputs, etc. So we will likely have to replicate styles from our existing UI components, without being able to use the components themselves.Make sure to reference react-dropdown-tree-select's styling tips, specifically the default class names so that you can select them while styling the outer component.
Relevant Figma designs
Mobile:
![image](https://user-images.githubusercontent.com/4369024/111064727-a6dcc300-8483-11eb-915c-f0b1a07f7ebe.png)
Desktop:
![image](https://user-images.githubusercontent.com/4369024/111064722-9e848800-8483-11eb-855f-5f5aa9175674.png)
Suggested branch name:
type-filtering
Suggested PR title (as would probably be suggested by @code-arman):
<some relevant emoji> Add type filtering
Refs #23
Learning objectives
Todo
IconButton
Search
component so it doesn't get too longMapContext
SearchContext
Useful links
useContext
hooks anywhere we need it.Additional notes
Type Hierarchy
parent_id
inGET /types.json
so we don't have to make additional GET requests for each type. Rebuilding the actual tree will probably be very fast compared to the overhead of making the network request, so this should work fine for now.Virtualization
The library we're using now supports virtualization out of the box, which means that DOM elements are only rendered as they scroll into view. Definitely great to have.
The text was updated successfully, but these errors were encountered: