0

Initially I used a GET request to call every single item in my MongoDB database to my frontend but now I'm trying to implement a filter system where users would narrow down the options presented by the database using filters.

Here is the concept of what i'm trying to do, this is what it looks like:

enter image description here

If someone selects the filter options "SDG 2: Zero Hunger", "1: Discussion Project", and "Demographic", the user will click submit and then only the first card that has all those things will show up on the right of it, not the second one underneath it.

I'm struggling as to how I would send the information as to how to filter the database because I get the error Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body.

How could I code it so that once a user clicks submit, it sends an object containing the filter table data, ex. const filterData = {sdg, assignment_type, theme} (where each refers to its respective thing), to the backend where I perform a GET request to the database in which I use the following code to pull the filtered data:

// filtering a project, calling this everytime filter is changed
const filterProject = async (req, res) => {
    const {sdg, assignment_type, theme} = req.body
    
    const filteredProjects = await Project.find({sdg: sdg, assignment_type: assignment_type, theme: theme})

    res.status(200).json(filteredProjects)
}

Here is the code for my filtering page right now:

// Filterpage.js
import ProjectDetails from '../ProjectDetails'
import Dropdown from './Dropdown'
import { useEffect, useState } from 'react'


const FilterBody = () => {
    const [projects, setProjects] = useState(null)

    useEffect(() => {
        const fetchProjects = async () => {
            const response = await fetch('/api/projects') // Change localhost to server name when deploying
            const json = await response.json() // contains array of projects

            if (response.ok) {
                setProjects(json)
            }
        } 

        fetchProjects()
    }, [])

    return (
        <div className="filterHome">
            <div className="filterTableContainer">
                <div className="filterTableTitle">
                    Filter Table
                </div>
                <div className="filterSDGDropDown">
                    <Dropdown />
                </div>
            </div>

            {/* Lists projects */}
            <div>
                <div className="projects">
                    {projects && projects.map((project) => (
                        <ProjectDetails key={project._id} project={project}/>
                    ))}
                </div>
            </div>
        </div>
    )
}

export default FilterBody

Here is the actual filter table, I'm calling this class in Filterpage.js // Dropdown.js - WHERE THE ACTUAL FILTER TABLE IS import React, { useEffect, useState } from 'react'

class Dropdown extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        sdg: 'SDG 1: No Poverty',
        assignment_type: 1,
        theme: 'Demographic'
    };
  
      this.handleSDGChange = this.handleSDGChange.bind(this);
      this.handleAssignmentChange = this.handleAssignmentChange.bind(this);
      this.handleThemeChange = this.handleThemeChange.bind(this);
      this.handleSubmit = this.handleSubmit.bind(this);
    }
    
    // Handling all 3 input changes
    handleSDGChange(event) {
      this.setState({sdg: event.target.value});
    }

    handleAssignmentChange(event) {
        this.setState({assignment_type: event.target.value});
    }

    handleThemeChange(event) {
        this.setState({theme: event.target.value});
    }

    // Handling all 3 input submissions
    handleSubmit(event) {
        alert(this.state.sdg + '--- Assignment Type: ' + this.state.assignment_type + '--- Theme: ' + this.state.theme);
        event.preventDefault();

        // TODO, SEND DATA TO BACKEND TO BE FILTERED
    }

    render() {
      return (
        <form onSubmit={this.handleSubmit}>
            <label>SDG:</label>
            <select value={this.state.sdg} onChange={this.handleSDGChange}>
              <option value="SDG 1: No Poverty">SDG 1: No Poverty</option>
              <option value="SDG 2: Zero Hunger">SDG 2: Zero Hunger</option>
              <option value="SDG 3: Good Health & Well Being">SDG 3: Good Health & Well Being</option>
            </select>

            <label>Assignment Type:</label>
            <select value={this.state.assignment_type} onChange={this.handleAssignmentChange}>
              <option value="1">1: Discussion Project</option>
              <option value="2">2: PDF Case study</option>
              <option value="3">3: Community Project</option>
            </select>

            <label>Theme:</label>
            <select value={this.state.theme} onChange={this.handleThemeChange}>
              <option value="Demographic">Demographic</option>
              <option value="Economical">Economical</option>
              <option value="Socio-cultural">Socio-cultural</option>
              <option value="Technological">Technological</option>
              <option value="Ecological">Ecological</option>
              <option value="Poltical">Poltical</option>
            </select>

            <input type="submit" value="Submit" />
        </form>
      );
    }
  }
export default Dropdown

Here is my projects.js routes backend code:

const express = require('express')
const {
    createProject,
    getProject,
    getProjects,
    deleteProject,
    updateProject,
    filterProject
} = require('../controllers/projectController')

const router = express.Router()

// GET all workouts
router.get('/', getProjects) // Base route for /api/projects

// FILTER workouts
router.get('/filter', filterProject)

// GET a single workout
router.get('/:id', getProject)

// POST all workouts
router.post('/', createProject)

// DELETE a single workout
router.delete('/:id', deleteProject)

// UPDATE a single workout
router.patch('/:id', updateProject)


module.exports = router

And here is my projectController.js which handles all the requests in the backend (i only included the relevant ones):

const Project = require('../models/projectModel')
const mongoose = require('mongoose')

// get all projects
const getProjects = async (req, res) => {
    const projects = await Project.find({}).sort({ createdAt: -1 }) // Specify 
    // const test = await Project.find({sdg: "SDG 1: No Poverty", assignment_type: 1})
    // console.log(test)
    res.status(200).json(projects)
}


// filtering a project, calling this everytime filter is changed
const filterProject = async (req, res) => {
    const {sdg, assignment_type, theme} = req.body
    
    const filteredProjects = await Project.find({sdg: sdg, assignment_type: assignment_type, theme: theme})

    res.status(200).json(filteredProjects)
}


module.exports = {
    getProjects,
    getProject,
    createProject,
    deleteProject,
    updateProject,
    filterProject
}

In addition, is there a way to use react context so that every time the user clicks submit, it will just update the results without refreshing the page?

Soccerball123
  • 741
  • 5
  • 17

0 Answers0