Job Listing Filtering React - reactjs
I'm having trouble figuring out how to filter this job listing that I found in frontend mentor.
The filtering partially works. For example, if I add HTML and Senior tag, it filters it correctly. But the logic isn't right cause I test it for other tags and the result doesn't come out as expected.
I appreciate any help to get pointed at the right direction.
this is my App.js code
import './App.css';
import axios from 'axios';
import React, {useState,useEffect} from "react";
import Card from "./components/card/Card";
import Header from "./components/header/Header";
import FilterBar from "./components/FilterBar/FilterBar";
function App() {
const [data, setData] = useState([]);
const URL = 'http://localhost:3000/data.json';
const [category, setCategory] = useState([]);
console.log("category is " + category);
useEffect(() => {
axios.get(URL).then((response) => {
setData(response.data);
//console.log(data);
});
}, []);
/*useEffect(() => {
}, []);*/
function addItem(item){
console.log("addItem " + item);
const duplicateItem = category.find((collection) => collection === item);
if(!duplicateItem){
setCategory([...category, item]);
} else {
alert(item + " is already in the list.");
}
}
function removeAllItems(items, counter){
if(counter > 0){
setCategory(items);
} else {
alert("There are no items in the filter bar to remove.");
}
}
return (
<div className="App">
<Header />
{
category.length > 0 ?
<FilterBar removeAllItems={removeAllItems} languages={category} />
:
""
}
{
Object.keys(data).map((item, index) => (
category.length < 1 ?
<Card
key={index}
data_company_name={data[item].company}
data_logo={data[item].logo}
data_new={data[item].new}
data_featured={data[item].featured}
data_position={data[item].position}
data_languages={data[item].languages}
data_level={data[item].level}
data_role={data[item].role}
data_posted_at={data[item].postedAt}
data_contract={data[item].contract}
data_location={data[item].location}
data_tools={data[item].tools}
addItem={addItem}
/>
: category.includes(data[item].level)
|| category.includes(data[item].role)
|| category.every((language) => data[item].languages.includes(language))
|| category.every((tool) => data[item].tools.includes(tool))
?
<Card
key={index}
data_company_name={data[item].company}
data_logo={data[item].logo}
data_new={data[item].new}
data_featured={data[item].featured}
data_position={data[item].position}
data_languages={data[item].languages}
data_level={data[item].level}
data_role={data[item].role}
data_posted_at={data[item].postedAt}
data_contract={data[item].contract}
data_location={data[item].location}
data_tools={data[item].tools}
addItem={addItem}
/>
: ""
))}
</div>
);
}
export default App;
This is the Card.js
import {StyledCard} from './Card.styled';
const Card = ({addItem, data_logo, data_company_name, data_new, data_featured, data_position, data_languages, data_level, data_role, data_contract, data_posted_at, data_location, data_tools}) => {
const data = data_languages.map( (language, index) => {
return <span onClick={() => addItem(language) } key={index} className={`role-tag-${index}`}>{language}</span>;
});
const tools_data = data_tools.map( (tool, index) => {
return <span key={index} onClick={() => addItem(tool) } className={`data-tools`}>{tool}</span>
});
return (
<>
<div className={`card-container`}>
<StyledCard>
<div className={`inside-card-wrapper`}>
<div className={`img`}>
<img src={data_logo} alt=""/>
<div className={`company-tag-wrapper`}>
<span className={`company-name`}>{data_company_name}</span>
{
data_new === true ?
<span className={`job-tag-new`}>NEW!</span>
:
""
}
{
data_featured === true ?
<span className={`job-tag-featured`}>FEATURED</span>
:
""
}
<div className={`role-title`}>
<div><strong>{data_position}</strong></div>
<div className={`role-tags`}>
<span onClick={() => addItem(data_role)} className={`data-role`}>{data_role}</span>
<span onClick={() => addItem(data_level) } className={`data-level`}>{data_level}</span>
{data}
{tools_data}
</div>
</div>
<div className={`job-type-wrapper`}>
<div className={`post`}>
<span>{data_posted_at}</span>
•
<span>{data_contract}</span>
•
<span>{data_location}</span>
</div>
</div>
</div>
</div>
</div>
</StyledCard>
</div>
</>
);
};
export default Card;
This is the FilterBar.js file
import {StyledFilterBar} from "./FilterBar.styled";
const FilterBar = ({removeAllItems, languages}) => {
//console.log("FilterBar.js " + items);
let counter = 0;
const data = languages.map( (item, index) => {
counter = languages.length;
return <div key={index}>{item} </div>
});
return (
<div>
<StyledFilterBar>
<div className={`filter-options`}>
<div className={`left-side`}>
{data}
</div>
<div className={`right-side`}>
<div onClick={() => removeAllItems([], counter) } className={`clear`}>clear</div>
</div>
</div>
</StyledFilterBar>
</div>
);
};
export default FilterBar;
This is the json file that contains the data
[
{
"id": 1,
"company": "Photosnap",
"logo": "./img/photosnap.svg",
"new": true,
"featured": true,
"position": "Senior Frontend Developer",
"role": "Frontend",
"level": "Senior",
"postedAt": "1d ago",
"contract": "Full Time",
"location": "USA Only",
"languages": ["HTML", "CSS", "JavaScript"],
"tools": []
},
{
"id": 2,
"company": "Manage",
"logo": "./img/manage.svg",
"new": true,
"featured": true,
"position": "Fullstack Developer",
"role": "Fullstack",
"level": "Midweight",
"postedAt": "1d ago",
"contract": "Part Time",
"location": "Remote",
"languages": ["Python"],
"tools": ["React"]
},
{
"id": 3,
"company": "Account",
"logo": "./img/account.svg",
"new": true,
"featured": false,
"position": "Junior Frontend Developer",
"role": "Frontend",
"level": "Junior",
"postedAt": "2d ago",
"contract": "Part Time",
"location": "USA Only",
"languages": ["JavaScript"],
"tools": ["React", "Sass"]
},
{
"id": 4,
"company": "MyHome",
"logo": "./img/myhome.svg",
"new": false,
"featured": false,
"position": "Junior Frontend Developer",
"role": "Frontend",
"level": "Junior",
"postedAt": "5d ago",
"contract": "Contract",
"location": "USA Only",
"languages": ["CSS", "JavaScript"],
"tools": []
},
{
"id": 5,
"company": "Loop Studios",
"logo": "./img/loop-studios.svg",
"new": false,
"featured": false,
"position": "Software Engineer",
"role": "Fullstack",
"level": "Midweight",
"postedAt": "1w ago",
"contract": "Full Time",
"location": "Worldwide",
"languages": ["JavaScript"],
"tools": ["Ruby", "Sass"]
},
{
"id": 6,
"company": "FaceIt",
"logo": "./img/faceit.svg",
"new": false,
"featured": false,
"position": "Junior Backend Developer",
"role": "Backend",
"level": "Junior",
"postedAt": "2w ago",
"contract": "Full Time",
"location": "UK Only",
"languages": ["Ruby"],
"tools": ["RoR"]
},
{
"id": 7,
"company": "Shortly",
"logo": "./img/shortly.svg",
"new": false,
"featured": false,
"position": "Junior Developer",
"role": "Frontend",
"level": "Junior",
"postedAt": "2w ago",
"contract": "Full Time",
"location": "Worldwide",
"languages": ["HTML", "JavaScript"],
"tools": ["Sass"]
},
{
"id": 8,
"company": "Insure",
"logo": "./img/insure.svg",
"new": false,
"featured": false,
"position": "Junior Frontend Developer",
"role": "Frontend",
"level": "Junior",
"postedAt": "2w ago",
"contract": "Full Time",
"location": "USA Only",
"languages": ["JavaScript"],
"tools": ["Vue", "Sass"]
},
{
"id": 9,
"company": "Eyecam Co.",
"logo": "./img/eyecam-co.svg",
"new": false,
"featured": false,
"position": "Full Stack Engineer",
"role": "Fullstack",
"level": "Midweight",
"postedAt": "3w ago",
"contract": "Full Time",
"location": "Worldwide",
"languages": ["JavaScript", "Python"],
"tools": ["Django"]
},
{
"id": 10,
"company": "The Air Filter Company",
"logo": "./img/the-air-filter-company.svg",
"new": false,
"featured": false,
"position": "Front-end Dev",
"role": "Frontend",
"level": "Junior",
"postedAt": "1mo ago",
"contract": "Part Time",
"location": "Worldwide",
"languages": ["JavaScript"],
"tools": ["React", "Sass"]
}
]
The problem is that you're combining all your "categories" into a single filter, but each category (language, tool, etc) has a different matching criteria. I think that the matching criteria you want is:
Any match for the job level or the job role
All match for tools and languages
But you can't do this without knowing the type of filter that you've got for each category.
So, there are a few ways you can solve that. One way would be to to separate out your filters by category. You could write a custom hook to do the heavy lifting:
const createEmptyFilter = () => ({
all: new Set(),
language: new Set(),
tool: new Set(),
role: new Set(),
level: new Set()
});
const useFilter = () => {
const [filter, setFilter] = useState(createEmptyFilter);
const handleAddFilter = (type, value) => {
if (!filter[type]) {
alert(`Unknown filter category: '${type}'`);
return;
}
setFilter((prev) => {
const next = { ...prev };
next.all = new Set(prev.all).add(value);
next[type] = new Set(prev[type]).add(value);
return next;
});
};
const handleClearFilter = () => setFilter(createEmptyFilter());
const matchesFilter = (item) => {
const { language, tool, role, level } = filter;
if (level.size && !level.has(item.level)) return false;
if (role.size && !role.has(item.role)) return false;
for (const l of language) {
if (!item.languages.includes(l)) return false;
}
for (const t of tool) {
if (!item.tools.includes(t)) return false;
}
return true;
};
return [
[...filter.all.values()],
handleAddFilter,
handleClearFilter,
matchesFilter
];
};
A couple of things to note:
The 'all' category is just to maintain the order of items that the user adds entries to the filter. You could compose this by combining the values from all the categories, but you'd lose the ordering.
Now that we know which category each filter belongs to, our filtering criteria can be more specific.
With the card, you'd have to add the category when you apply a filter, for example:
<span
onClick={() => onAddFilter("role", data_role)}
className={`data-role`}
>
Here's an updated sample.
Related
How do I populate a graph from react-google-charts with data from a rest api?
I'm starting my studies in react and I'm not able to display the api data in the graph. The chart renders blank. function ParticipationChart() { const [chartData, setChartData] = useState([]); useEffect(() => { axios.get(`${BASE_URL}`) .then((res) => { setChartData(res.data.users); console.log(res.data.users) }) .catch((error) => { console.log(error.response) }) }, []); return ( <div className="pieContainer"> <Chart chartType="PieChart" width="100%" height="280px" data={[ ['users name', 'users participation'], ...chartData.map(users => [users.name, users.participation]) ]} options={options} /> </div> ) } The api returns the data like this: { "users": [ { "id": "1674259593624", "name": "Carlos", "lastname": "Moura", "participation": "5" }, { "id": "1674259666544", "name": "Fernanda ", "lastname": "Oliveira", "participation": "15" }, { "id": "1674259711245", "name": "Hugo", "lastname": "Silva", "participation": "20" }, { "id": "1674259994192", "name": "Eliza", "lastname": "Souza", "participation": "20" }, { "id": "1674782074696", "name": "Anderson", "lastname": "Santos", "participation": "40" } ] } I tried a lot of things but i can't show the data. I can display local data normally, but external data is not working.
React Redux QUIZ
I am trying to make a simple Quiz work with Redux following this example in https://www.codeproject.com/Articles/5130417/Quiz-Application-in-React-Using-Redux . Somehow I think the quizLoad Reducer is not getting the data or isn't even being called correctly. This is my Reducer: const QUIZ_LOAD = 'QUIZ_LOAD'; const QUIZ_ANSWER = 'QUIZ_ANSWER'; const QUIZ_SUBMIT = 'QUIZ_SUBMIT'; const PAGER_UPDATE = 'PAGER_UPDATE'; const INITIAL_STATE = { quiz: { config: { 'allowBack': false, 'allowReview': false, 'autoMove': true, // if true, it will move to next question automatically when answered. 'duration': 0, // indicates the time in which quiz needs to be completed. 0 means unlimited. 'pageSize': 1, 'requiredAll': false, // indicates if you must answer all the questions before submitting. 'richText': false, 'shuffleQuestions': false, 'shuffleOptions': false, 'showClock': false, 'showPager': true, 'theme': 'none' }, questions: [] }, mode: 'quiz', pager: { index: 0, size: 1, count: 1 } } export default (state = INITIAL_STATE, action) => { const { type, payload } = action; console.log('REDUCERRRRRRRRR') switch (type) { case PAGER_UPDATE: return { ...state, pager: payload, mode: 'quiz' }; case QUIZ_LOAD: return { ...state, quiz: payload }; case QUIZ_SUBMIT: return { ...state, mode: payload }; case QUIZ_ANSWER: return { ...state, quiz: payload }; default: return state; } }; // <<<ACTIONS>>> export const pagerUpdate = (payload) => { return { type: PAGER_UPDATE, pager: payload, mode: 'quiz' }; }; export const quizLoad = (payload) => { return { type: QUIZ_LOAD, quiz: payload }; }; export const quizSubmit = (payload) => { return { type: QUIZ_SUBMIT, mode: { payload } }; }; export const quizAnswer = (payload) => { return { type: QUIZ_ANSWER, quiz: { payload } } }; This is my component and where I get the error "Unhandled Rejection (TypeError): Cannot read property 'config' of undefined eval C:\Users\Willkommen\Documents\MyPension\REPOs\web-best\src\pages\header\vertragsCheck\index.js:69:6" import React from "react"; import { connect } from "react-redux"; import Quiz from "./quiz/Quiz"; import { pagerUpdate, quizLoad } from "redux/vertragsCheck/vertragscheckReducer"; import SEOTitle from "components/SEO/seoTitle"; import WavySectionWrapper from "components/Layouts/Containers/wavySectionWrapper/wavySectionWrapper"; import WavyPageTitleWrapper from "components/Sections/WavyPageTitle/WavyPageTitle"; import Button from "components/Button/Button"; import "./vertragsCheckSteps.scss"; const bgMobileImage = "/images/illustrations/pages/Home/mobile/mobile-phone1.png"; class vertragsCheck extends React.Component { state = { // quizes: [ // { id: 'data/myPensionQuiz.json', name: 'VertragsCheck' }, // { id: 'data/myPensionTest.json', name: 'Rente' } // ], quizVisible: false, quizId: "quizApi/quiz.json" }; pager = { index: 0, size: 1, count: 1 }; componentDidMount() { this.load(this.state.quizId); } load(quizId) { let url = quizId || this.props.quizId; fetch(`../${url}`) .then(res => res.json()) .then(res => { let quiz = res; quiz.questions.forEach(q => { q.options.forEach(o => (o.selected = false)); }); debugger; console.log("quizCONFIG", this.props.quiz); quiz.config = Object.assign(this.props.quiz.config || {}, quiz.config); this.pager.count = quiz.questions.length / this.pager.size; this.props.onQuizLoad(quiz); this.props.onPagerUpdate(this.pager); }); } // onChange = (e) => { // this.setState({ quizId: e.target.value }); // this.load(e.target.value); // } handleClick = () => { const { quizVisible } = this.state; this.setState({ quizVisible: !quizVisible }); }; render() { const quizVisible = this.state.quizVisible; if (!quizVisible) { return ( <WavySectionWrapper vertical> <SEOTitle page="vertrags-check" /> <WavyPageTitleWrapper> <div className="flex-container"> <div> <h1> Kostenloser <br /> Vertrags-Check </h1> <p> Ist meine bestehender Vertrag zu teuer? <br /> Wie schneidet meine bestehen Altervorsorge ab? <br /> Wir helfen Dir Deine Altervorsorge zu optimieren. </p> <Button size="sm" onClick={this.handleClick}> Jetzt prüfen </Button> </div> <div> <img src={bgMobileImage} alt="myPension mobile graphic" /> {/* <img src="/images/background-elements/bg-vertical-section.svg" /> */} </div> </div> </WavyPageTitleWrapper> </WavySectionWrapper> ); } else if (quizVisible) { return ( <Quiz quiz={this.state.quiz} quizId={this.state.quizId} mode={this.state.mode} /> ); } } } const mapStateToProps = state => { return { ...state.quiz }; }; const mapDispatchToProps = dispatch => ({ onQuizLoad: payload => dispatch({ type: quizLoad, payload }), onPagerUpdate: payload => dispatch({ type: pagerUpdate, payload }) }); export default connect( mapStateToProps, mapDispatchToProps )(vertragsCheck); And this is my quiz data in public folder: { "id": 1, "name": "Vertrags-check Quiz", "description": "Vertrags-check Quiz determines if your actual pension contract is improvable", "config": { "showPager": false, "allowBack": true, "autoMove": true }, "questions": [ { "id": 1010, "name": "Sind die Effektivkosten höher als 1,5%?", "questionTypeId": 1, "options": [ { "id": 1055, "questionId": 1010, "name": "Ja", "isAnswer": false }, { "id": 1056, "questionId": 1010, "name": "Nein", "isAnswer": false }, { "id": 1057, "questionId": 1010, "name": "Weiß nicht", "isAnswer": true } ], "questionType": { "id": 1, "name": "test type", "isActive": true } }, { "id": 1011, "name": "Liegt Dein Rentenfaktor unter 27€?", "questionTypeId": 1, "options": [ { "id": 1055, "questionId": 1010, "name": "Ja", "isAnswer": false }, { "id": 1056, "questionId": 1010, "name": "Nein", "isAnswer": false }, { "id": 1057, "questionId": 1010, "name": "Weiß nicht", "isAnswer": true } ], "questionType": { "id": 1, "name": "test type", "isActive": true } }, { "id": 1012, "name": "Erfolgt die Anlage zu weniger als 80% in Aktien?", "questionTypeId": 1, "options": [ { "id": 1055, "questionId": 1010, "name": "Ja", "isAnswer": false }, { "id": 1056, "questionId": 1010, "name": "Nein", "isAnswer": false }, { "id": 1057, "questionId": 1010, "name": "Weiß nicht", "isAnswer": true } ], "questionType": { "id": 1, "name": "test type", "isActive": true } }, { "id": 1013, "name": "Ist Deine Rendite geringer als 3% p.A.?", "questionTypeId": 1, "options": [ { "id": 1055, "questionId": 1010, "name": "Ja", "isAnswer": false }, { "id": 1056, "questionId": 1010, "name": "Nein", "isAnswer": false }, { "id": 1057, "questionId": 1010, "name": "Weiß nicht", "isAnswer": true } ], "questionType": { "id": 1, "name": "test type", "isActive": true } }, { "id": 1014, "name": "Zahlst Du für Flexibilität?", "questionTypeId": 1, "options": [ { "id": 1055, "questionId": 1010, "name": "Ja", "isAnswer": false }, { "id": 1056, "questionId": 1010, "name": "Nein", "isAnswer": false }, { "id": 1057, "questionId": 1010, "name": "Weiß nicht", "isAnswer": true } ], "questionType": { "id": 1, "name": "test type", "isActive": true } }, { "id": 1015, "name": "Es gibt keine Steuervorteile bei deinem bestehendem Vertrag?", "questionTypeId": 1, "options": [ { "id": 1055, "questionId": 1010, "name": "Ja", "isAnswer": false }, { "id": 1056, "questionId": 1010, "name": "Nein", "isAnswer": false }, { "id": 1057, "questionId": 1010, "name": "Weiß nicht", "isAnswer": true } ], "questionType": { "id": 1, "name": "test type", "isActive": true } }, { "id": 1016, "name": "Hast Du Deinen Vertrag nach 2005 abgeschlossen?", "questionTypeId": 1, "options": [ { "id": 1055, "questionId": 1010, "name": "Ja", "isAnswer": false }, { "id": 1056, "questionId": 1010, "name": "Nein", "isAnswer": false }, { "id": 1057, "questionId": 1010, "name": "Weiß nicht", "isAnswer": true } ], "questionType": { "id": 1, "name": "test type", "isActive": true } } ] }
There is problem probably here: const mapStateToProps = state => { return { ...state.quiz } }; You are using object spread operator, which puts/maps content of the state.quiz into your props. Therefore there isn't any quiz in this.props. Try to map the state.quiz to this.props.quiz this way: const mapStateToProps = state => { return { quiz: state.quiz } }; You are also mapping actions to props incorrectly, try this: const mapDispatchToProps = dispatch => ({ onQuizLoad: payload => dispatch(quizLoad(payload)), onPagerUpdate: payload => dispatch(pagerUpdate(payload)) });
Displaying list dynamically in react when user click on input filed
I am trying to display list dynamically when user click on input box. for that I took onChange event handle on input box and setting state to new data when user click on input box. but it is not giving me desired result. can anyone help me to solve the issue ? When user click on input box then only list should be displayed but in my case it's displaying already. SearchBox.js import React, { Component } from "react"; import SourceData from "../assets/continents.json"; class SearchBox extends Component { state = { value: "" }; handleChange = e => { this.setState({ sourceData: SourceData }); }; render() { const searhBox = ( <input type="text" value={this.state.value} onClick={this.handleChange} /> ); const selectBox2 = SourceData.map(option => <li>{option.continent}</li>); return ( <React.Fragment> <h2>Step 1</h2> <h3>Select a continent.</h3> {searhBox} <ul>{selectBox2}</ul> </React.Fragment> ); } } export default SearchBox continents.json [ { "continent": "Africa", "countries": [ { "name": "Nigeria", "flag": "ð³ð¬" }, { "name": "Ethiopia", "flag": "ðªð¹" }, { "name": "Egypt", "flag": "ðªð¬" }, { "name": "DR Congo", "flag": "ð¨ð©" }, { "name": "South Africa", "flag": "ð¿ð¦" } ] }, { "continent": "America", "countries": [ { "name": "USA", "flag": "ðºð¸" }, { "name": "Brazil", "flag": "ð§ð·" }, { "name": "Mexico", "flag": "ð²ð½" }, { "name": "Colombia", "flag": "ð¨ð´" }, { "name": "Argentina", "flag": "ð¦ð·" } ] }, { "continent": "Asia", "countries": [ { "name": "China", "flag": "ð¨ð³" }, { "name": "India", "flag": "ð®ð³" }, { "name": "Indonesia", "flag": "ð®ð©" }, { "name": "Pakistan", "flag": "ðµð°" }, { "name": "Bangladesh", "flag": "ð§ð©" } ] } ] output ::
In SearchBox.render, build up the list of countries from this.state.sourceData const selectBox2 = this.state.sourceData.map(option => <li>{option.continent}</li>); return ( <React.Fragment> <h2>Step 1</h2> <h3>Select a continent.</h3> {searhBox} {selectBox2 && <ul>{selectBox2}</ul>} </React.Fragment> ); Also, remember to set an initial value for sourceData in SearchBox.state. state = { value: '', sourceData: [] };
react/api - how to parse and map an array inside of api response
I'm trying to parse and map through the array "items" inside of this api response [ { "id": "", "portal_account_id": "", "platform": "", "current_date": "2018-07-30T11:27:16+02:00", "email": "", "items": [ { "itemId": "123", "name": "vacuum 1", "img": "" }, { "itemId": "456", "name": "vacuum 2", "img": "" }, { "itemId": "789", "name": "vacuum 3", "img": "" } ] } ] this is what I have tried, it just parse through the response itself but I want to parse through the array inside of this response. this.props.items.map((item) => { return ( <Col className='' xs={12} md={4} key={item.id}> <ProductItem handleOnAdd={this.dispachAddToCart.bind(this)} item={item} /> </Col> ); })
Suppose this is your array; const response = [ { "id": "", "portal_account_id": "", "platform": "", "current_date": "2018-07-30T11:27:16+02:00", "email": "", "items": [ { "itemId": "123", "name": "vacuum 1", "img": "" }, { "itemId": "456", "name": "vacuum 2", "img": "" }, { "itemId": "789", "name": "vacuum 3", "img": "" } ] }, { "id": "", "portal_account_id": "", "platform": "", "current_date": "2018-07-30T11:27:16+02:00", "email": "", "items": [ { "itemId": "123", "name": "vacuum 1", "img": "" }, { "itemId": "456", "name": "vacuum 2", "img": "" }, { "itemId": "789", "name": "vacuum 3", "img": "" } ] } ]; Then in render method do this. render() { return ( {response.map(item => { return ( <div key={item.id}> {item.items.map(product => { return ( <div key={product.itemId}> <p>{product.name}</p> <p>path of image{product.img}</p> </div> ); })} </div> ) })} ); } The problem is you get an array of objects, and inside each object there is another array of objects.
You are probably getting JSON res from your API. You can destruct items from it and then iterate over it. render(){ const { items } = this.props.response items.map((item)=>{ return ( // do the stuff here ) }) }
Do you mean you just want to parse the first item of the response array: this.props.items[0].items.map
ReactJs:Trying to get value of a select menu when button is clicked
i'm trying to figure out how for each item rendered, inside that item i want to get the value of the select menu when i click the button. i've tried creating a variable inside the render but it's bound to all of the rendered items. export const products = React.createClass({ getInitialState() { return { prods: [ { "name": "T-Shirt", "image_full": "550.jpeg", "image_thumb": "415.jpeg", "options": [ { "sku": "TGT-SHIRT-S", "name": "Small", "price": 21.95 }, { "sku": "TGT-SHIRT-M", "name": "Medium", "price": 21.95 }, { "sku": "TGT-SHIRT-L", "name": "Large", "price": 21.95 }, { "sku": "TGT-SHIRT-XL", "name": "X-Large", "price": 21.95 }, { "sku": "TGT-SHIRT-2XL", "name": "2X-Large", "price": 23.95 }, { "sku": "TGT-SHIRT-3XL", "name": "3X-Large", "price": 23.95 } ] }, { "name": "T-Shirt 2", "image_full": "550.jpeg", "image_thumb": "415.jpeg", "options": [ { "sku": "TGT-SHIRT-S", "name": "Small", "price": 21.95 }, { "sku": "TGT-SHIRT-M", "name": "Medium", "price": 21.95 }, { "sku": "TGT-SHIRT-L", "name": "Large", "price": 21.95 }, { "sku": "TGT-SHIRT-XL", "name": "X-Large", "price": 21.95 }, { "sku": "TGT-SHIRT-2XL", "name": "2X-Large", "price": 23.95 }, { "sku": "TGT-SHIRT-3XL", "name": "3X-Large", "price": 23.95 } ] } ], cart: [] } }, render() { let prodlist = this.state.prods.map(pp => <div className="col-md-2"> <img src={pp.image_full} alt={pp.title} width="100%" /> <select ref="ppt"> <option value="null" selected>Select Option</option> {pp.options.map(opts => <option value={opts.sku}>{opts.name}</option>)} </select> <button className="btn btn-primary btn-block">ADD TO CART</button> </div> ) return ( <div> {prodlist} </div> ); } }); export default products
You can store selected id (or scu in your example) in onChange on select onChange = (e) => { this.setState({selectedScu: e.target.value}); } And get it from the list on button click options.find(option => option.scu === this.state.selectedScu)