'website breaks when trying to .map through two select filters
I am creating a website with custom cards to displays companys and a sidebar filter. The data comes from an Array of Objects (Datalist.js). My problem is that the website breaks as soon as I try to loop through crypto. The problem does not exist with country.
I assume it happens because (crypto is an object in the object) and therefore .map doesn't work because its only for arrays.
any tips?
Datalist.js
export const data = [
{
id:1,
name:"Digitec",
description:"wir akzeptieren folgende Kryptowährungen als Zahlungsmittel:",
logo:"brack.jpg",
website:"https://www.galaxus.ch/de",
forward:"Onlineshop besuchen",
crypto: {
btc:"btc.png",
doge:"doge.png",
eth:"eth.png",
usdt:"usdt.png",
},
country: "Schweiz",
tag:"E-commerce"
},
{
id:2,
name:"Galaxus",
description:"wir akzeptieren folgende Kryptowährungen als Zahlungsmittel:",
logo:"brack.jpg",
website:"https://www.galaxus.ch/de",
forward:"Webseite besuchen",
crypto: {
btc:"btc.png",
doge:"doge.png",
eth:"eth.png",
usdt:"usdt.png",
},
country: "Schweiz",
tag:"Immobilien"
},
{
id:3,
name:"Unplugged Performance",
description:"wir akzeptieren folgende Kryptowährungen als Zahlungsmittel:",
logo:"unplugged.jpg",
website:"https://unpluggedperformance.com/",
forward:"Webseite besuchen",
crypto: {
btc:"btc.png",
doge:"doge.png",
eth:"eth.png",
ltc:"ltc.png",
},
country: "Amerika",
tag:"Automobil"
},
{
id:4,
name:"Galaxus",
description:"wir akzeptieren folgende Kryptowährungen als Zahlungsmittel:",
logo:"brack.jpg",
website:"https://www.galaxus.ch/de",
forward:"Webseite besuchen",
crypto: {
btc:"btc.png",
doge:"doge.png",
eth:"eth.png",
usdt:"usdt.png",
},
country: "Schweiz",
tag:"Automobil"
},
{
id:5,
name:"Galaxus",
description:"wir akzeptieren folgende Kryptowährungen als Zahlungsmittel:",
logo:"brack.jpg",
website:"https://www.galaxus.ch/de",
forward:"Webseite besuchen",
crypto: {
btc:"btc.png",
doge:"doge.png",
eth:"eth.png",
usdt:"usdt.png",
},
country: "Schweiz",
tag:"Gastronomie"
},
{
id:6,
name:"Galaxus",
description:"wir akzeptieren folgende Kryptowährungen als Zahlungsmittel:",
logo:"brack.jpg",
website:"https://www.galaxus.ch/de",
forward:"Webseite besuchen",
crypto: {
btc:"btc.png",
doge:"doge.png",
eth:"eth.png",
usdt:"usdt.png",
xmr:"xmr.png",
},
country: "Schweiz",
tag:"Lebensmittelhändler"
},
{
id:7,
name:"Galaxus",
description:"wir akzeptieren folgende Kryptowährungen als Zahlungsmittel:",
logo:"brack.jpg",
website:"https://www.galaxus.ch/de",
forward:"Webseite besuchen",
crypto: {
btc:"btc.png",
doge:"doge.png",
eth:"eth.png",
usdt:"usdt.png",
},
country: "Schweiz",
tag:"Lebensmittelhändler"
},
{
id:8,
name:"Galaxus",
description:"wir akzeptieren folgende Kryptowährungen als Zahlungsmittel:",
logo:"brack.jpg",
website:"https://www.galaxus.ch/de",
forward:"Webseite besuchen",
crypto: {
btc:"btc.png",
doge:"doge.png",
eth:"eth.png",
usdt:"usdt.png",
},
country: "Schweiz",
tag:"Medizin"
},
{
id:9,
name:"Galaxus",
description:"wir akzeptieren folgende Kryptowährungen als Zahlungsmittel:",
logo:"brack.jpg",
website:"https://www.galaxus.ch/de",
forward:"Webseite besuchen",
crypto: {
btc:"btc.png",
eth:"eth.png",
doge:"doge.png",
usdt:"usdt.png",
},
country: "Schweiz",
tag:"Gastronomie"
},
{
id:10,
name:"Galaxus",
description:"wir akzeptieren folgende Kryptowährungen als Zahlungsmittel:",
logo:"brack.jpg",
website:"https://www.galaxus.ch/de",
forward:"Webseite besuchen",
crypto: {
btc:"btc.png",
doge:"doge.png",
eth:"eth.png",
usdt:"usdt.png",
},
country: "Schweiz",
tag:"Medizin"
},
]
FilterBar.js
import React, {useState} from 'react'
function FilterBar({countries, cryptos, onNameFilter, onCountryFilter, onCryptoFilter}) {
const [filters, setFilters] = useState({
name: "",
country: "",
crypto: "",
});
const handleInput = (field) => (event) => {
const {value} = event.target;
setFilters({
...filters,
[field]: value,
})
switch(field) {
case "name":
onNameFilter(value);
break;
case "country":
onCountryFilter(value);
break;
case "crypto":
onCryptoFilter(value);
break;
default:
break;
}
};
return (
<div className="row my-5">
<div className="col sticky">
<h4 className="border-bottom">Filters</h4>
</div>
<div className="col-sm-12 my-2">
<input
type="text"
className="forms-control"
id="name"
value={filters.name}
placeholder="company name"
onChange={handleInput ("name")}
></input>
</div>
<div className="col-sm-12 my-2">
<label htmlFor="country">country</label>
<select className="form-control" id="country" onChange={handleInput ("country")}>
<option value="select">Select</option>
{countries.map((country) => (
<option value={country} key={country}>{country}</option>
))}
</select>
</div>
<div className="col-sm-12 my-2">
<label htmlFor="crypto">Cryptocurreny</label>
<select className="form-control" id="crypto" onChange={handleInput ("crypto")}>
<option value="select">Select</option>
{cryptos.map((crypto) => (
<option value={crypto} key={crypto}>{crypto}</option>
))}
</select>
</div>
</div>
)
}
export default FilterBar
PersonItem.js
import React from 'react'
function PersonItem({item}) {
return (
<div className="col-sm-12 col-md-4">
<div className="card-my-2 text-center">
<img src={item?.image} className="card-img-top" alt="" />
<div className="card-body">
<h5 className="card-title">
{item?.name}
</h5>
<h5 className="card-description">{item?.description}</h5>
{Object.values(item.crypto).map((imgName, index) => (
<img key={index}
className="cryptoImg"
alt="crypto"
variant="top"
src={`./images/${imgName}`} />
))}
<button className="card-text" src={item?.website}>Shop besuchen</button>
</div>
</div>
</div>
)
}
export default PersonItem
App.js
import {useState} from "react";
import './App.css';
import {data} from "./Datalist";
import FilterBar from "./components/FilterBar";
import PersonItem from './components/PersonItem';
function App() {
const [allData, setAllData] = useState(data);
/*generating new Array with filtered data for country dropdown*/
const generateCountryDataForDropdown = () => {
return [...new Set(data.map((item) => item.country))];
};
/*generating new Array with filtered data for currency dropdown*/
const generateCryptoDataForDropdown = () => {
return [...new Set(data.map((item) => item.crypto))];
};
/*filter name function*/
const handleFilterName = (event) => {
const filteredData = data.filter((item) => {
if (item.name.toLowerCase().includes(event.toLowerCase())) {
return item;
}
});
setAllData(filteredData);
};
/*filter country function*/
const handleFilterCountry = (country) => {
const filteredData = data.filter((item) => {
if (item.country === country) {
return country;
}
});
setAllData(filteredData);
};
/*filter crypto function*/
const handleFilterCrypto = (crypto) => {
const filteredData = data.filter((item) => {
if (item.crypto === crypto) {
return crypto;
}
});
setAllData(filteredData);
};
return (
<div className="container">
<div className="row">
<div className="col-sm-3">
<FilterBar
countries={generateCountryDataForDropdown()}
cryptos={generateCryptoDataForDropdown()}
onNameFilter={handleFilterName}
onCountryFilter={handleFilterCountry}
onCryptoFilter={handleFilterCrypto}
/>
</div>
<div className="col-sm-9">
<div className="row mt-5">
{allData.map((item) => (
<PersonItem item={item} key={item.id} />
))}
</div>
</div>
</div>
</div>
);
}
export default App;
Solution 1:[1]
In your app.js [...new Set(data.map((item) => item.crypto))] will return an array of objects.
So in FilterBar.js you cant give
{cryptos.map((crypto) => (
<option value={crypto} key={crypto}>{crypto}</option>
))}
because crypto is object with keys btc,doge etc.
You could try
Object.keys(cryptos).map((crypto) => (
<option value={crypto} key={crypto}>{crypto}</option>
))}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | rahuuzz |
