How to get data in reactjs when we select checkbox without reloading? - javascript

I am trying to make an project in which data loads when we click on the checkbox in reactjs , for example we have this :
<h1> Please select an type </h1>
<input type="checkbox" id="Bike" name="Bike" value="Bike" />
<input type="checkbox" id="car" name="car" value="car" />
And then when we select the bike checkbox, our component loads and shows items from JSON file that only contains bikes without reloading or clicking the submit button
Just like how we search on the react-icon website where we type our input and icons load without reloading the whole page or clicking the submit button, thanks :)

whenever there is a change in your checkbox function
e.target.value will give you the selected data
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value,
});
}
You can create a custom onChange function :
<input
type="checkbox"
name="check"
checked={this.state.check}
onChange={(e) => {
this.handleChange({
target: {
name: e.target.name,
value: e.target.checked,
},
});
}}
/>

(In this example I've used radio buttons to simplify things.)
When the checked status of a button is changed call an event handler. This updates the radio button status, and then calls the API with the button id. The API sends back the relevant data, and the handler updates the data state with that.
When the state changes (the state array has length > 0) create a table using the data in state.
const { useState } = React;
// Sample data
const data={bike:[{id:1,name:"Bike1",type:"Type1"},{id:2,name:"Bike2",type:"Type2"}],car:[{id:1,name:"Car1",type:"Car1"},{id:2,name:"Car2",type:"Car2"}]};
// Mock API that sends data based on the
// id it's passed after two seconds
function mockApi(id) {
return new Promise(res => {
setTimeout(() => {
res(JSON.stringify(data[id]));
}, 2000);
});
}
function Example() {
// Two states: one to hold the button status, the
// other to hold the data
const [ radio, setRadio ] = useState({});
const [ data, setData ] = useState([]);
// Destructure the id from the button dataset,
// set the button state, and then get the data using
// that id. When the data is returned update the data state
function handleChange(e) {
const { id } = e.target.dataset;
setRadio(id);
mockApi(id)
.then(res => JSON.parse(res))
.then(setData);
}
// Create an array of cell data
function createCells(obj) {
return Object.values(obj).map(value => {
return <td>{value}</td>;
});
}
// Create an array of rows
function createRows(data) {
return data.map(obj => {
return <tr>{createCells(obj)}</tr>;
});
}
// Add some Radio components, and a table
// When the data state is changed, and the state
// contains some data, create a table
return (
<div>
<div>
<Radio
id="car"
name="radio"
checked={radio === 'car'}
handleChange={handleChange}
/>
<Radio
id="bike"
name="radio"
checked={radio === 'bike'}
handleChange={handleChange}
/>
</div>
<div className="output">
{data.length
? (
<table>
<thead>
<td>#</td>
<td>Name</td>
<td>Type</td>
</thead>
<tbody>{createRows(data)}</tbody>
</table>
)
: 'No data'}
</div>
</div>
);
}
// Returns a Radio component
function Radio({ id, checked, handleChange }) {
return (
<label>
<span>{id}</span>
<input
type="radio"
data-id={id}
checked={checked}
onChange={handleChange}
/>
</label>
);
}
ReactDOM.render(
<Example />,
document.getElementById('react')
);
[type="radio"]:hover { cursor: pointer; }
.output { margin-top: 1em; }
label span { text-transform: uppercase; }
table { border-collapse: collapse; }
thead { background-color: #343434; color: white; }
td { padding: 0.25em 0.5em; border: 1px solid darkgray; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>

this is a simple sample.
const TestCheckBox = () => {
const [carvalue, setCarValue] = useState(false);
const [Bikevalue, setBikeValue] = useState(false);
return (
<>
<h1> Please select an type </h1>
<input
type="checkbox"
onChange={({ target }) => setBikeValue(target.checked)}
id="Bike"
name="Bike"
value="Bike"
/>
<label>{Bikevalue ? "bike Checked" : "bike Unchecked"}</label>
<div>
<input
type="checkbox"
onChange={({ target }) => setCarValue(target.checked)}
id="car"
name="car"
value="car"
/>
<label>{carvalue ? "Car Checked" : "Car Unchecked"}</label>
</div>
</>
);
};
You can use this method
const [value, setValue] = useState({});
const checkHandle=({target})=>{
let temp={...value,
[target.name]:target.checked
};
}

Related

How to Handle multiple radio button inputs with one onChange function handler

i have a scenario where based on a number(say numberOfFlags) i want to render numberOfFlags times an radio button group.Each group has two radio buttons approve and reject as per screenshot attached how to get values of all inputs when they change?
An lastly i have to store result of all radio buttons (approve/reject) in an array and send to API
You need to use two parameters on onChange function. One is for current index and another is for Approve/Reject.
Like below code snippet
onchange = handleOnChage(index, isApproveClicked)
You can achive this in many different ways, but I would probably simple create a state with an array of values in the parent component and pass it to each and every item to toggle its own state depending action.
App.js
export function App() {
const [list, setList] = useState([false, false, false]);
const updateItem = (value, index) => {
let copyList = [...list];
copyList[index] = !value;
setList(copyList);
};
console.log(list)
return (
<div className="App">
{list && (
<>
{list.map((value, index) => (
<Item values={[value, index]} updateItem={updateItem} key={index+"_check"} />
))}
</>
)}
</div>
);
}
Item.js
export default function Item({ values, updateItem }) {
return (
<>
<input
onChange={() => updateItem(values[0], values[1])}
type="checkbox"
checked={values[0] ? "checked" : ""}
/>
</>
);
}
Presented below is one possible way to achieve the desired objective.
Code Snippet
const {useState} = React;
const Thingy = ({...props}) => {
// num-of-flags is obtained from props
const { numOfFlags: nf} = props || {};
// if it is null or not above 0, return "invalid" message to parent
if (!(nf && nf > 0)) return "invalid num-of-flags";
// state variable to store approve/reject status
const [statusObj, setStatusObj] = useState({});
// JSX to render the UI & handle events
return (
<div>
{([...Array(nf).keys()].map(grpIdx => (
<div className="grpBox">
Group num {grpIdx+1} <br/>
<input type='radio' name={grpIdx} id={grpIdx} value={'approve'}
onChange={() => setStatusObj({
...statusObj, [grpIdx]: 'approve',
})}
/>
<label for={grpIdx}>Approve</label>{" "}
<input type='radio' name={grpIdx} id={grpIdx} value={'reject'}
onChange={() => setStatusObj({
...statusObj, [grpIdx]: 'reject',
})}
/>
<label for={grpIdx}>Reject</label>
</div>
)))}<br/>
<button
onClick={() => {
// make API call here
// for verification, displaying an alert-message showing the status
const displayMsg = [...Array(nf).keys()].map(
gi => "Group num " + (+gi+1) + " : " + (gi in statusObj ? statusObj[gi] : '__')
).join(', ');
alert(`Approve-Reject status is: ${JSON.stringify(displayMsg)}`);
}}
>
Submit
</button>
</div>
);
};
ReactDOM.render(
<div>
<div className="demoTitle">DEMO</div>
<Thingy numOfFlags={5} />
</div>,
document.getElementById("rd")
);
.demoTitle {
margin-bottom: 5px;
font-size: 20px;
text-decoration: underline;
}
.grpBox {
margin: 5px; padding: 10px;
border: 2px solid purple;
width: max-content;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="rd" />
Explanation
Inline comments added to the snippet above.
PS: If you'd like to add value to stackoverflow community,

Inserting only unique ID in form value in React

I am new to React, there are two input fields in the application, one is for ID and another for Name, There are two components I've used, in the parent component I've maintained all the state and form in separate another component. My aim is to check the id which is a input from the user, id should be unique every time, if it's same, an alert should popup and the focus turns to ID input field, and it should do the same until the ID is different from all the objects(state object)
My app.js file is,
import React, { Component } from "react";
import Form from "./Form";
export default class App extends Component {
state = {
names: [
/*
{id: 1,name: "Aashiq"}
*/
],
};
renderTable() {
return this.state.names.map((eachName) => {
const { id, name } = eachName;
return (
<tr key={id}>
<td>{id}</td>
<td>{name}</td>
<td>
<input
type="button"
value="Delete"
onClick={() => this.deleteName(eachName.id)}
/>
</td>
</tr>
);
});
}
deleteName = (id) => {
console.log("ID object", id);
this.state.names &&
this.setState({
names: this.state.names.filter((name) => name.id !== id),
});
};
addName = (newName) => {
this.setState({
names: [newName, ...this.state.names],
});
};
render() {
return (
<>
<Form onSubmit={this.addName} names={this.state.names} />
{/* Table */}
<br />
<table id="details">
<tbody>
<tr>
<th>ID</th>
<th>Names</th>
<th>Operation</th>
</tr>
{/* Render dynamic rows
*/}
{this.renderTable()}
</tbody>
</table>
</>
);
}
}
You can see I try to render the data as table and we can delete the row data also
The form.js file is,
import React, { useState } from "react";
// import { uniqueId } from "lodash";
export default function Form(props) {
const [name, setName] = useState("");
const [id, setId] = useState();
const handleSubmit = (e) => {
e.preventDefault();
handleChangeandValidate();
};
const handleChangeandValidate = () => {
const { onSubmit, names } = props;
console.log("Object keys length", Object.keys(names).length);
if (Object.keys(names).length !== 0) {
names.map((name) => {
if (name.id === id) {
alert("Enter unique id");
setId("");
document.getElementById("ID").focus();
} else {
//if different id
onSubmit({ id: id, name: name });
setName("");
setId("");
}
return null;
});
} else {
onSubmit({ id: id, name: name }); // first time
setName("");
setId("");
}
};
return (
<form onSubmit={handleSubmit} id="myform">
<label style={{ fontSize: "20px", fontWeight: "bold" }}>
Name: {""}
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
required
/>
</label>{" "}
<label style={{ fontSize: "20px", fontWeight: "bold" }}>
ID: {""}
<input
type="number"
onChange={(e) => setId(e.target.value)}
required
value={id}
id="ID"
/>
</label>
{""}
<input type="submit" value="Submit" />
</form>
);
}
You can see I've tried to get the state and onSubmit function from the parent component(app.js) and done some logic like comparing all the ID's, but this logic throws some error, please somebody come up with a good solution.
Thanks in advance!
I have modified your code a bit and here is a working example.
Here is what I did:
I used createRef() to create two references that refer to each input field named nameInputRef and idInputRef.
I added ref={nameInputRef} and ref={idInputRef} so that we can get their values on submit.
On submit, I get the values of the name + id using their refs.
to search for whether the ID exists or not, I used Array.find() which would return undefined if the same id doesn't exist in the list of names coming from the props.
in addName(), I used setState() but in the param I used a function to make sure I get the latest list of names as updating the state is asynchronous. Inside I also used ES6's destructuring feature to make a copy of the current list, push the new name to it and then update the state with the new list of names.

How to implement a check all button for radio buttons, using React Hooks?

Don't get this confused with checking each radio button I have on the page. I want to implement a check all button that sets the value of a nested object state equal to a certain value. I am storing each question in a nested state. Ex.
formQuestions({
kitchen: [question,question2,question3],
living: [question,question2,question3]
})
Four radio buttons are being made for each question. Now one radio button can only be selected at once. Each radio button has its' own value. Ex. `"Good", "Fair", "Poor", "N/A".
When a radio button is selected a state is generated dynamically for that section and question. Ex.
formAnswers({
kitchen: {
question: "Good"
question2: "Poor"
}
})
The goal here is the button that I want to create that checks only one value for each question Ex. clicks button question: "Good", question2: "Good" etc..
For me to set the state of a dynamic value I would need the "Section name" lets call it Name and the "Question" we'll call it question. That would give me access to the value like so formAnswers[Name][question]: value
I am trying to set that state from a component called SectionHeader. These contain the buttons.
SectionHeader.js
import { FormAnswersContext, FormQuestionsContext } from "../../Store";
function SectionHeader({ title, name }) {
const [formAnswers, setFormAnswers] = useContext(FormAnswersContext);
const [formQuestions, setFormQuestions] = useContext(FormQuestionsContext);
return (
<div>
<h1 className={styles["Header"]}>{title}</h1>
<div className={styles["MarkAllWrapper"]}>
<button className={styles["MarkAll"]}>
Mark all items as "Good" in this section
</button>
<br />
<button className={styles["MarkAll"]}>
Mark all items as "N/A" in this section
</button>
</div>
</div>
);
}
The parent of Section Header and the rest of the form code excluding the child radio buttons which I have explained, are in another component LivingRoom.js
LivingRoom.js
import { FormQuestionsContext, FormAnswersContext } from "../../Store";
function LivingRoomForm({ Name }) {
const [expanded, setExpanded] = useState(false);
const [formQuestions, setFormQuestions] = useContext(FormQuestionsContext);
const [formAnswers, setFormAnswers] = useContext(FormAnswersContext);
const array = formQuestions.living;
const onChange = (e, name) => {
const { value } = e.target;
setFormAnswers((state) => ({
...state,
[Name]: { ...state[Name], [name]: value },
}));
};
const handleOpen = () => {
setExpanded(!expanded);
};
return (
<div>
<Button
className={styles["CollapseBtn"]}
onClick={handleOpen}
style={{ marginBottom: "1rem", width: "100%" }}
>
<p>LIVING ROOM INSPECTION</p>
<FontAwesome
className="super-crazy-colors"
name="angle-up"
rotate={expanded ? null : 180}
size="lg"
style={{
marginTop: "5px",
textShadow: "0 1px 0 rgba(0, 0, 0, 0.1)",
}}
/>
</Button>
<Collapse className={styles["Collapse"]} isOpen={expanded}>
<Card>
<CardBody>
{array ? (
<div>
<SectionHeader title="Living Room Inspection" name={Name} />
<div
className={styles["LivingRoomFormWrapper"]}
id="living-room-form"
>
{array.map((question, index) => {
const selected =
formAnswers[Name] && formAnswers[Name][question]
? formAnswers[Name][question]
: "";
return (
<div className={styles["CheckboxWrapper"]} key={index}>
<h5>{question}</h5>
<Ratings
section={Name}
question={question}
onChange={onChange}
selected={selected}
/>
</div>
);
})}
</div>
<br />
<ImageUploader name="living" title={"Living Room"} />
</div>
) : (
<div></div>
)}
</CardBody>
</Card>
</Collapse>
</div>
);
}
If there is anything I am missing please let me know, I would be happy to share it. Cheers
Edit: for anyone that needs the radio buttons component.
Ratings.js
import React from "react";
import { FormGroup, CustomInput } from "reactstrap";
function Ratings({ selected, section, question, onChange }) {
return (
<div>
<FormGroup>
<div>
<CustomInput
checked={selected === "Good"}
onChange={(e) => onChange(e, question)}
type="radio"
id={`${section}_${question}_Good`}
value="Good"
label="Good"
/>
<CustomInput
checked={selected === "Fair"}
onChange={(e) => onChange(e, question)}
type="radio"
id={`${section}_${question}_Fair`}
value="Fair"
label="Fair"
/>
<CustomInput
checked={selected === "Poor"}
onChange={(e) => onChange(e, question)}
type="radio"
id={`${section}_${question}_Poor`}
value="Poor"
label="Poor"
/>
<CustomInput
checked={selected === "N/A"}
onChange={(e) => onChange(e, question)}
type="radio"
id={`${section}_${question}_NA`}
value="N/A"
label="N/A"
/>
</div>
</FormGroup>
</div>
);
}
I do not completely understand your question, I am sorry but I think this will help you.
Here is an implementation of radio buttons using react -
class App extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
handleChange = e => {
const { name, value } = e.target;
this.setState({
[name]: value
});
};
render() {
return (
<div className="radio-buttons">
Windows
<input
id="windows"
value="windows"
name="platform"
type="radio"
onChange={this.handleChange}
/>
Mac
<input
id="mac"
value="mac"
name="platform"
type="radio"
onChange={this.handleChange}
/>
Linux
<input
id="linux"
value="linux"
name="platform"
type="radio"
onChange={this.handleChange}
/>
</div>
);
}
}
After a few attempts, I was able to figure out the solution to this issue.
The key here was to figure out a way to get gather each question so that it may be used as a key when setting the state. As my questions were stored in a ContextAPI, I was able to pull them out like so...
this may not be the best solution however it worked for me.
const setStateGood = () => {
formQuestions[name].map((question) => {
setFormAnswers((state) => ({
...state,
[name]: { ...state[name], [question]: "Good" },
}));
});
};
const setStateNA = () => {
formQuestions[name].map((question) => {
setFormAnswers((state) => ({
...state,
[name]: { ...state[name], [question]: "N/A" },
}));
});
};
I was able to map through each question since the name is being passed through props is a key inside the actual object, formQuestions[name]. Because i'm mapping through each one I can set that question as a key and return the new state for each question to whatever I would like.
However, if I was to create an onClick={setState('Good')}, React didn't like that and it created an infinite loop. I will look for more solutions and update this post if I find one.

Adding an input tag dynamically in React, shows for a moment then disappears

What am trying to do is to be able to add an input field dynamically.
So for example, once you fill your first hobby, then you decide to add another one. you click on add and a new input field is shown.
The input field is showing for split second then disappearing.
Code:
class App extends React.Component {
state = {
Hobbies: []
}
addHobby = () => {
this.setState(prevState => ({ Hobbies: [...prevState.Hobbies, ''] }))
}
handleChange(i, event) {
let Hobbies = [...this.state.Hobbies];
Hobbies[i] = event.target.value;
this.setState({ Hobbies });
}
removeClick(i) {
let Hobbies = [...this.state.Hobbies];
Hobbies.splice(i, 1);
this.setState({ Hobbies });
}
render() {
const widthStyle = {
width: '15rem'
};
return (
<div className="App">
<form >
<label>
Hobbies:
<input type="text" name="hobby" />
</label>
<br /><br />
{
this.state.Hobbies.map((el, i) => {
return (
<div key={i}>
<input type="text" value={el || ''} onChange={this.handleChange.bind(this, i)} />
<input type='button' value='remove' onClick={this.removeClick.bind(this, i)} />
</div>
)
})
}
<button onClick={this.addHobby.bind(this)}>ADD Hobby</button>
</form>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('container'));
The problem is you are clicking inside a form which is why your page is getting refreshed(form submits) and you lose the state
addHobby = (e) => {
e.preventDefault() //<-----
this.setState({ Hobbies: [...this.state.Hobbies, ''] })
}
CodeSandbox
An alternative to using e.preventDefault() is to mark the button as being of type="button" the default inside a <form> element is type="submit" which automatically submits the form/refreshes the page.
<button type="button" onClick={this.addHobby.bind(this)}>ADD Hobby</button>
Setting `type="button" indicates that the button is just there to trigger some JavaScript action, not to submit the form.

Filtering data in table in React based on values of radio buttons and input field after hitting submit failed

I have data from local json file that I use to create a table.
In Table class component I have the table contains top 10 movies. The data is being displayed from filteredData state variable and are well displayed after loading the table. Above table I have 2 radio buttons, to choose whether I want to search data based on column title or column genre saved in state variable radioSearch by using function searchHandler. Then I have an input field, when I enter a string in it the result is being saved in searchFieldInput state variable, by using updatedSearch function.
Finally, I have submitHandler function in this component to filter the table based on selected radio button(title/genre of the film), and after that based on entered string in input field. The filtered data I am putting into filteredData variable in order to update the state by using setState. Unfortunately no filtering is being done after hitting submit. In Table component is nested TableRow component which should display the data based on applied filtering. I don't know whether the concept of submitHandler function is wrong, and why is not filtering the data? Can somebody help.
Here is my Table component:
import React, {Component} from 'react';
import TableRow from './TableRow/TableRow';
class Table extends Component {
constructor(props) {
super(props)
this.state = {
filteredData: this.props.data,
searchFieldInput: '',
radioSearch: this.props.radioSearch,
transformed: false
}
}
updatedSearch = (event) => {
this.setState({
searchFieldInput: event.target.value
})
}
searchHandler = (e) => {
this.setState({
radioSearch: e.target.value
})
};
submitHandler = (event) => {
event.preventDefault();
if(this.state.radioSearch === "title") {
let filteredData = this.props.data.filter(column => {
return column.title.toLowerCase().indexOf(this.state.searchFieldInput.toLowerCase()) !== -1;
});
this.setState({
filteredData: filteredData
});
return this.state.filteredData;
} else if(this.state.radioSearch === "genre"){
let filteredData = this.props.data.filter(column => {
return column.genre.toLowerCase().indexOf(this.state.searchFieldInput.toLowerCase()) !== -1;
});
this.setState({
filteredData: filteredData
});
return this.state.filteredData;
}
console.log(this.state.radioSearch);
}
render() {
let filteredData = this.props.data.filter(column => {
return column.title.toLowerCase().indexOf(this.state.searchFieldInput.toLowerCase()) !== -1;
});
return(
<React.Fragment>
<div className="container-fluid">
<div className="container">
<form>
{/*Search field*/}
<input
className={"Search" + (this.state.transformed === true ?
' transformed' : '')}
type="text"
placeholder={(this.state.transformed === true ?
'' : 'Type here')}
maxLength="20"
value={this.state.searchFieldInput} required
onChange={this.updatedSearch.bind(this)}
/>
<button type="submit">
Search
</button>
{/*Radio buttons*/}
<label htmlFor="title">
<input type="radio" name="title" id="title" value="title" checked={this.state.radioSearch === "title"}
onChange={this.searchHandler}/>
title
</label>
<label htmlFor="genre">
<input type="radio" name="genre" id="genre" value="genre" checked={this.state.radioSearch === "genre"}
onChange={this.searchHandler}/>
genre
</label>
</form>
</div>
<div className="container">
<table>
<thead>
<tr>
<th>No.</th>
<th>Picture</th>
<th>Release date</th>
<th>Genre</th>
<th>Rating</th>
</tr>
</thead>
<tbody>
{this.state.filteredData.map((row, index) => {
return (
<TableRow
numeration={index + 1}
key={row.id}
row={row}
/>
)
})
}
</tbody>
</table>
</div>
</div>
</React.Fragment>
)
}
}
export default Table;
I think its because you forgot to add the function to the submit button:
<button type="submit" onSubmit={this.submitHandler.bind(this)}>
Search
</button>

Categories

Resources