I'm creating a Todo App as an exercise in learning PostgreSQL and functional programming in javascript. The idea is there can be multiple containers each with separate filter settings, each reading from a master list of Todos, then each container displays it's results based on it's filter settings. This is really all done in React-Redux, and Nodejs, but I made the examples below to better illustrate the problem.
The Data:
// Example todos
let a = {
added: "2021-02-01T05:00:00.000Z",
completed: null,
description: "This is just a test.",
name: "testing",
tags: [],
todo_id: 3,
}
let b = {
added: "2021-02-01T05:00:00.000Z",
completed: null,
description: "This is just a test.",
name: "testing",
tags: ["one", "two"],
todo_id: 4
}
let c = {
added: "2021-02-01T05:00:00.000Z",
completed: null,
description: "This is just a test.",
name: "tesin",
tags: ["one"],
todo_id: 5
}
let d = {
added: "2021-02-01T05:00:00.000Z",
completed: '2021-03-01T05:00:00.000Z',
description: "This is just a test.",
name: "testing",
tags: ["two", "testing"],
todo_id: 6
}
// Example filter_group
// This is just to show what the initial state looks like in my React app
const filter_groups = {
"main": {
byTag: 'two',
byName: '',
byCompleted: true
}
}
// Object.keys(filter_groups).map() passes the filter settings down as props
// Just stuck it in a variable for the example
const filter = filter_groups['main']
// Putting example Todos in array
const todo_list = [a,b,c,d]
The current solution is pretty simple, ugly, and inefficient. It applies each filter one at a time:
// ------- CURRENT SOLUTION -------
// if user is trying to filter byCompleted, then filter todo_list
// else do nothing todo_list and pass it to the next filter
// (similar thing applies down the chain)
const byCompleted = filter.byCompleted === true ?
todo_list.filter ( (t) => {
return t.completed !== null
})
:
todo_list
//IF user is trying to filter byTag...
const byTag = filter.byTag !== '' ?
// THEN filter the byCompleted array above
byCompleted.filter( (t) => {
// IF there are tags on the Todo...
let matches = t.tags ?
// THEN filter for matches
t.tags.filter( (tag) => {
return tag === filter.byTag
})
:
// ELSE make this an empty array
[]
// return any Todos with match
return matches.length > 0
})
:
byCompleted
// IF user is trying to filter byName...
const byName = filter.byName !== '' ?
// THEN filter byTag Todos
byTag.filter( (t) => {
return t.name === P.filter.byName
})
:
byTag
console.log(byName);
I really want to know if there's a way to apply the entire filter all at once. In the example you'll see the filter is set to byTag: 'two', byComplete: true which makes the console print out only one result. My past attempts at getting things to work with one filter pass would return everything with the two tag.
I tried looking at the documentation and saw there's more going on in the filter function, but it just didn't click, and I couldn't find any examples that fit my use case very well.
Edit: Here's it all on codesandbox: https://codesandbox.io/s/recursing-almeida-cdz65?file=/src/index.js
