Approach on FILTER structure and its general logic
A few month ago I worked on the filters for a cellphone company hotsale event. Before start coding, it is important to establish the general logic and structure of this development. In this article you will find an example on how to raise this issue.
The idea is that you can continue the next step (translate this into code) with the tools you choose. Even so, in a future article maybe I'll show you how to turn this logic into code with reactJS, as a reference.
Without further introductions, let's begin:
Requirements
The user can:
- apply filters on a specific products collection (hotsale).
- do infinite scrolling on products loading.
- accumulate filters in the search.
- maintain filters when reloading the page.
- pass the URL to another person and this person will see same filters applied.
Problems
The main problem here was the first requirement, because the ERP the company uses has native filters, but they cannot be applied to a specific collection. So, this involved building the filters from scratch.
The solution was for the client to load the id
of the collection in a placeholder and the Front End
takes this datum to add it as a parameter in the product searches. This will allow the possibility of using the filters with other collections (when changing the id) or none (leaving the placeholder empty).
Another central issue was to consider that in the visible URL to the user, could arrive parameters external to this development (such as analytics tools or purchase conditions indicators) or parameters with incorrect ids or incorrect or contradicted values (typos).
Therefore, the last three requirements involve special attention when reading the URL.
Data structure
First of all, we must decide how to save the data of our filters. Suppose we have a variable called bodyFilters
. It can be an array of objects, where each one represents a specific criterion of the filter, which in turn contains several options. For example, a filter criterion can be by brand:
var bodyFilters = [
{
criterionId: 'brands',
criterionName: 'BRANDS:',
criterionOptions: [
{
id: 'brands-samsung',
name: 'Samsung',
param: 'fq=B:126'
}, {...}, {...}, {...}
]
}, {...}, {...}, {...}
];
It is important that bodyFilters
is an array so you can loop over it and apply for each criterion the logic that builds its view. Same consideration for the criterionOptions
. Note that each option is an object that have an id
to identify it, a name
that will appear in the view and the param
that will be necessary to build the URL and do the request.
We will also need a variable activeFilters
, whose structure will be the same asbodyFilters
, because: 1) we will use its data to update activeFilters
and 2) we will cross both arrays data in order to determine which options are selected (maybe in the view they have a different colour or font weight).
Behaviour (part 1)
Second, we determine the flux of the development when the page loads:
- get
bodyFilters
Of course, when the page loads, the first thing we want to do is get the bodyFilters
. In the best case we can use static data, but it is very likely that we have to make one or more request (for example, in my case, in order to obtain the values of the brands, specifications and ids of each one, with which the search parameters are built) and parse its data.
Probably, the bodyFilters
value will not vary frequently, so we can store it in the cache and update it when necessary.
- get
activeFilters
Now we read the URL and, crossing the data of bodyFilters
, we identify if there are valid params. With this result we map bodyFilters
and getactiveFilters
(remember to consider if there is a default `activeFilters').
- create or update URLs
Once we have got the activeFilters
we can use the params from each selected option and:
- create the URL to do the request.
- update the URL web page we
history.replaceState()
.
I suggest making these URLs as similar as possible. Then, once the URL to do the request is ready:
fetchProducts
And then we use the response (maybe need to parse it) to show the products or the error if exists.
Behaviour (part 2)
Third, we consider the interactions:
handleFilterClick(currentCriterion, selectedOption)
When the user clicks for selecting or removing a filter option, we call this function that updates activeFilters
. Note that we need to pass currentCriterion
and selectedOption
as params in order to know which option to update. And, after activeFilters
is updated, repeat steps 3 and 4.
- Infinite scrolling
The typical situation is that in the URL of the fetchProducts
request, there is a field that indicates the page number. For example, pageNumber = 1
. For the infinite scrolling
we will need some more tools:
- A variable that indicates the
pageNumber
, whose default value is 1. - A function that checks if we must fetch products of the next page. Call it
checkNextPage
. For example, in my filters, at the bottom of the list there is a button. I check if that button is in viewport. If it is vissible, add +1 topageNumber
. - Listen the scroll event with a debounce and pass the above function.
- If the
pageNumber
updates, then update the URLs and repeat steps 3 and 4. - Remember to reset
pageNumber
to 1 whenhandleFilterClick
, that is step5.
Finally, what happens when there are no more products? How to avoid checkNextPage
function adds +1 to pageNumber
over and over again?
- We need to create a boolean
isNextPage
. It istrue
by default and everytime we reset the search (handleFilterClick
). But, if thefetchProducts
returns success and empty products, we setisNextPage
tofalse
. - Remember, of course, to use this boolean inside
checkNextPage
. The idea is something like this:
if (isNextPage && isBottomOfList) setNextPagePlusOne()
- Next, as I said earlier, if the
pageNumber
updates, then update the URLs and repeat steps 3 and 4.
Conclusion
With this approach, we first define a data structure for the bodyFilters
and activeFilters
that consists of an array of objects, each representing a criterion and containing an array of options.
Second, we summarize the basic operation of a filter with infinite scroll in six steps: the first four related to the operation when loading the web page, and the other two related to user interactions.
It is not quantum physics. However, it is important to take a moment and consider a global view of the structure and logic of the FILTER before starting to program. This will simplify your code and prevent you from entering labyrinths or dead ends.
Be free to use this approach, improve it and build something great with it!