Good day! I am hoping to get some help with a project I am working on. I created a filter functionality so that when a user click on a button, they can filter my projects based on what type of project it is.
I was able to get the "ALL" button to work but the other buttons are not working. The expected output is when I click on the button it filters out the other projects and keeps the one that matches the category. However the current output is when I click on the button, the projects disappear.
This is my code:
import React, {useState} from "react";
import ReactDOM from "react-dom";
import styles from "./projects.module.scss";
import cards from "./allData";
function Projects() {
const [state, setState] = useState(cards);
const handleBtns = (e) => {
let word = e.target.value;
function isCardActive() {
for(const card of cards) {
if (cards.category === "FEATURED") {
return true;
} else if (cards.category === "WEB APP") {
return true;
} else if (cards.category === "MOBLE APP"){
return true
}
}
};
if(word === 'All') {
setState(cards)
} else if(word === 'Featured') {
const filtered = cards.filter(isCardActive);
setState(filtered);
} else if(word === 'webApp') {
const filtered = cards.filter(isCardActive);
setState(filtered);
} else if(word === 'mobileApp') {
const filtered = cards.filter(isCardActive);
setState(filtered);
}
}
return(
<div className={styles.projects} id="projectHash">
<section>
<h3>PROJECTS</h3>
</section>
<section id={styles.filterMain}>
<button className={`${styles.filterBox} ${styles.active}`} onClick={handleBtns} type="button" value="All" >VIEW ALL</button>
<button className={styles.filterBox} onClick={handleBtns} type="button" value="Featured" >FEATURED</button>
<button className={styles.filterBox} onClick={handleBtns} type="button" value="webApp" >WEB APP</button>
<button className={styles.filterBox} onClick={handleBtns} type="button" value="mobileApp" >MOBILE APP</button>
</section>
<section>
{state.map((cards) => (
<div className={styles.projectcard} key={cards.id} >
<h4>Project Name: {cards.title} </h4>
<br/>
<h4>{cards.image}</h4>
</div>
))}
</section>
</div>
)
};
export default Projects;
This is code for the file that contains the array of data
import card1 from "../../assets/card1.jpg";
import card2 from "../../assets/card2.jpg";
import card3 from "../../assets/card3.jpg";
import card4 from "../../assets/card4.jpg";
import card5 from "../../assets/card5.jpg";
import card6 from "../../assets/card6.jpg";
const cards = [
{
title: 'VICTORY FOLIO',
category: ['WEB APP', 'FEATURED'],
description: 'Lorem ipsum dolro sit amt, consestcuer elit',
image: card1,
id: 1
},
{
title: 'IN WHOLENESS PRACTICE',
category: 'WEB APP',
description: 'Lorem ipsum dolro sit amt, consestcuer elit',
image: card2,
id: 2
},
{
title: 'TRIBE HAIRCARE',
category: ['WEB APP', 'MOBILE APP', 'FEATURED'],
description: 'Lorem ipsum dolro sit amt, consestcuer elit',
image: card3,
id: 3
},
{
title: 'TRIBE SKINCARE',
category: ['WEB APP', 'MOBILE APP'],
description: 'Lorem ipsum dolro sit amt, consestcuer elit',
image: card4,
id: 4
},
{
title: 'BUG TRACKER',
category: 'WEB APP',
description: 'Lorem ipsum dolro sit amt, consestcuer elit',
image: card5,
id: 5
},
{
title: 'PATIENT PORTAL',
category: 'MOBILE APP',
description: 'Lorem ipsum dolro sit amt, consestcuer elit',
image: card6,
id: 6
}
];
export default cards;
CodePudding user response:
So there's a whole lot going on in this that makes it not work, but basically your isCardActive does nothing because it doesn't receive the current card item to compare against.
I've created a sandbox here with how it should work, using useState and useEffect to filter the results when the filter (currentCard) changes. I've removed the styling, but you can add that back pretty easy.
And the code is here:
const [cards, setCards] = useState(allCards);
const [currentCard, setCurrentCard] = useState("All");
const handleBtns = (e) => {
let word = e.target.value;
setCurrentCard(word);
};
useEffect(() => {
if (currentCard === "All") {
setCards(allCards);
} else {
const filtered = allCards.filter((card) => {
return (
card.category === currentCard || card.category.includes(currentCard)
);
});
setCards(filtered);
}
}, [currentCard]);
return (
<div className="App">
<div id="projectHash">
<section>
<h3>PROJECTS</h3>
</section>
<section>
<button onClick={handleBtns} type="button" value="All">
VIEW ALL
</button>
<button onClick={handleBtns} type="button" value="FEATURED">
FEATURED
</button>
<button onClick={handleBtns} type="button" value="WEB APP">
WEB APP
</button>
<button onClick={handleBtns} type="button" value="MOBILE APP">
MOBILE APP
</button>
</section>
<h3>Current: {currentCard}</h3>
<section>
{cards.map((card) => (
<div key={card.id}>
<h4>Project Name: {card.title} </h4>
</div>
))}
</section>
</div>
</div>
);
CodePudding user response:
You can use Array.filter() method, also change the inputs values to match categories as they are defined in cards with uppercase and spaces between
const handleBtns = (e) => {
const word = e.target.value;
if (word === "All") setState(cards);
else {
const filteredCards = cards.filter(({ category }) => {
return category.includes(word);
});
setState(filteredCards);
}
};
CodePudding user response:
Here's a sandbox with my solution using the useState hook: codesandbox
I would note:
- When comparing string values, make sure that they use the same format/capitalization:
'Feature' === 'FEATURE' //false
'FEATURE' === 'FEATURE' //true
- Normalize data in your objects. JavaScript is dynamically typed, so it's ok to do this:
card.category = 'string'
card.category = ['STRING']
Making sure data types are the same removes the need to do extra checks in your filter function.