ReactJS - how to auto refresh after submitting form - html

When i submit the page never stops loading and i have to manually refresh the page to get the input in my table. the table.js and submit.js is in two different components. So how do i make my page automatically refresh alternativly if i could add som eventlistner in the table component to get the API again after a submit.
class Submit extends Component {
render() {
return (
<>
<form action='http://localhost:3001/api/post' method="POST" onsubmit="return false">
<input type="input" class="text" name="brand" placeholder="Brand" required />
<input type="input" class="text" placeholder="Model" required />
<input type="input" class="text" name="price" placeholder="Price" required />
<button type="submit" class='button'>Submit</button>
</form>
</>
)
}
}
function Table() {
useEffect(() => {
Axios.get("http://localhost:3001/api/get/carmodels").then((response) => {
setCarModelList(response.data)
})
}, [])
const [carModelList, setCarModelList] = useState([])
const DeleteCar = (val) => {
const next = [...carModelList];
const removedItems = next.splice(next.indexOf(val), 1);
const deleteCarModel = Axios.delete(`http://localhost:3001/api/delete/${val.id}`);
setCarModelList(next);
return deleteCarModel
}
const renderTableData = () => {
return carModelList.map((val) => (
<tr class>
<td>{val.id}</td>
<td>{val.brand}</td>
<td>{val.model}</td>
<td>{val.price}</td>
<td>
<button id="delete" onClick={() => DeleteCar(val)}>Delete</button>
</td>
</tr>))
}
return (
<table id="table">
<thead>
<tr>
<th>Id</th>
<th>Brand</th>
<th>Model</th>
<th>Price</th>
</tr>
</thead>
<tbody>
{renderTableData()}
</tbody>
</table>
);
}

code exampleAdd UseState for another alert variable that is initialized to false, when you click the submit button, you make it true, and after you fetch, you turn it back to false. example in the image attached
const [alert, setAlert] = useState(true);
const handleSubmit= (e)=> {
setAlert(true)
useEffect(()=>{
// perform your fetch
setAlert(false)
},[alert])
}

Related

React.js datatable data filter by datepicker and get sum value of column

import React, { useEffect, useState } from "react";
import axios from "axios";
import { Form } from "react-bootstrap";
function SalesReport() {
const [Data, setData] = useState([]);
useEffect(() => {
fetchData();
}, []);
const fetchData = () => {
axios.get("http://localhost:4000/api/cash/showInvoices").then((res) => {
const getData = res.data.data;
setData(getData);
});
};
return (
<div className="row">
<div className="card">
<div className="card-body">
<div className="d-inline-flex col-2 m-2">
<Form.Group controlId="dob">
<Form.Label>Start Date</Form.Label>
<Form.Control
type="date"
name="startDate"
placeholder="Date of Birth"
/>
</Form.Group>
<div className="ms-3">
<Form.Group controlId="dob">
<Form.Label>End Date</Form.Label>
<Form.Control
type="date"
name="enddate"
value={}
placeholder="Date of Birth"
/>
</Form.Group>
</div>
<div className="ms-2 mt-4">
<button className="btn btn-secondary btn-lg" type="button">
Print
</button>
</div>
</div>
<table
id="datatable-buttons"
className="table table dt-responsive nowrap w-100"
>
<thead>
<tr>
<th width="100px">Date</th>
<th>Invoice Id</th>
<th>Pay Method</th>
<th>Total</th>
<th>Customer Id</th>
<th>Cart Id</th>
</tr>
</thead>
<tbody>
{Data &&
Data.map((items) => {
return (
<tr>
<td> {new Date(items.date).toLocaleDateString()}</td>
<td>{items.invoice_id}</td>
<td>{items.pay_method}</td>
<td>{items.total}</td>
<td>{items.customer_id}</td>
<td>{items.inovice_cart_id}</td>
</tr>
);
})}
</tbody>
<tfoot>
<tr className="text-black font-weight-bol">
<td>
<h5 className="total-label">Grand Total</h5>
</td>
<td className="total-col">
<label></label>
</td>
<td className="total-col">
<label></label>
</td>
<td className="total-col">
<label>2234</label>
</td>
<td className="total-col">
<label></label>
</td>
<td className="total-col">
<label></label>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
);
}
export default SalesReport;
**backend**
*router.js*
const {
getInvoice,
viewInvoiceByDate,
} = require("./cashManagement.controller");
const router = require("express").Router();
const cors = require("cors");
router.get("/showInvoices", getInvoice);
module.exports = router;
*controller.js*
const { getInvoice, viewInvoiceByDate } = require("./cashManagement.service");
module.exports = {
getInvoice: (req, res) => {
getInvoice((err, results) => {
if (err) {
console.log(err);
return;
}
return res.json({
success: 1,
data: results,
});
});
},
}
*service.js*
const pool = require("../../config/database");
module.exports = {
getInvoice: (callBack) => {
var todayDate = new Date().toISOString().slice(0, 10);
pool.query(
`SELECT * FROM cash_management WHERE date='${todayDate}'`,
(errors, results, fields) => {
if (errors) {
return callBack(errors);
}
return callBack(null, results);
}
);
},
}
That picture shows what I'm trying to do. by default today's relevant data show. it took from using "new Date()" method using with mysql select query . So , if I want to get particular days period data , I should select it from data picker. There is two datapickers . one for starting date, second one for end data selecting. if I select just start date , I need data from that day to today . otherwise if I select just endDate , I need to get data from today to end date . so I tried to that someways. It doesn't work properly. My backend code here ,it contains how I got data from database . I just got data from using "newDate()" method to took today data. how it should be changed when entering start date and end date . otherwise here table you can see the total column . and table footer has "GrandTotal " 4th column should get the total values of "total columns" previously I took it direct from database. but now cant , because it is changed by quickly. I think you have clear idea about issue. I tried many ways , but it didn't work. if there any expert help me to solve the issue.

Display multiple dynamic input fields in react, based on a changing state variable?

So, I am building my first React app, that connects to a Flask backend. I have a specific functional component that fetches a dictionary from the Python program, and I have saved this in a state variable(done using useState, setVariables).
The object is of type
{'A':'x', 'B':'y', 'C':2},
and these are variable, and each render needs to be dynamic, based only on this object.
Based on the current state of this object, I want to display key-value pairs of this object in
<label>insertkey</label>
<input type="text" name = "insertkey" value=insertvalue/>
In addition, I want to be able to save any changes made to these values, and write into the state variable, so that I can send them back to my Flask backend.
I tried looping through each, and inserting as follows:
const [fields, setFields] = useState({});
//intermediate code for fetching and setting the state
useEffect(() => {
for (const [key, value] of Object.entries(fields)) {
console.log(`${key}:${value}`);
insert = insert + `<label> ${key} </label> <input type = 'text' value = ${value} name = ${key} onChange=${changedData()}></input><br/>`
}
document.getElementById('fields_form').innerHTML = insert;
});
const changedData = (evt) => {
setFields({ [evt.target.name]: evt.target.value });
console.log(evt.target.value);
}
//some intermediate code
return (
<div>
<form onSubmit={submitFunction}>
<p id='fields_form'>
</p>
<input type="submit" value="Submit"></input>
</form>
</div>
);
But when I do this, the state is set as 'Undefined'.
I would love to hear about some ways to implement this. Maybe it's a really small fix, and I'm missing it, or perhaps there is a different approach that could be more suitable.
Simple:
const Form = () => {
const [values, setValues] = useState({});
const onChange = (e) => {
const name = e.target.name;
let value = e.target.value;
setValues({ ...values, [name]: value });
};
const onSubmit = (e) => {
// send data or save it to local store
api.send(values)
};
return (
<form encType="multipart/form-data">
<input
type="text"
name="email"
value={value["email"]}
onChange={onChange}
/>
<input
type="text"
name="subject"
value={value["subject"]}
onChange={onChange}
/>
<input
type="text"
name="body"
value={value["body"]}
onChange={onChange}
/>
>
<button type="submit" onClick={onSubmit}>
Save
</button>
</form>
);
};
export default Form;
console.log(values);
It's your solution.
const [fields, setFields] = useState({});
const [values, setValues] = useState({});
// some fetch logic
// happens on loading some data
// for example data structure look's like:
// fetchedData = {
// email: 'email#placeholder'
// subject: 'subject placeholder'
// body: 'body placeholder'
// }
useEffect(() => {
if (fetchedData) {
setFields(fetchedData)
}
}, [fetchedData]);
// happens on fields changed
useEffect(() => {
if (fields) {
setValues(fields)
}
}, [fields]);
const changedData = (evt) => {
setValues({ ...values, [evt.target.name]: evt.target.value });
}
return (
<div>
<form onSubmit={submitFunction}>
{Object.keys(fields).map(_ => (
<input
type="text"
name={_}
value={values[_]}
onChange={changedData}
/>
))}
<input type="submit" value="Submit"></input>
</form>
</div>
);

How to delete particular array shown in grid and need to pass the id of the array?

I have created the simple grid and I have remove button in every table row.
If any data in db, it's shown in the view and if user need to add more file,clicking on add new button,my modal array(Colum in code) push the empty array to view.
The problem is while clicking 3rd index array remove button it's remove the first index of the array.
And how to pass the id to service if any id present. Now I hard coded in delete method.
For understanding please view the image.
HTML:
<div>
<form>
<h3 style="text-align:center">Knowledge Base</h3>
<br>
<table class="table table-striped">
<thead>
<tr>
<th scope="col">
File Name
</th>
<th scope="col">
Updated By
</th>
<th scope="col">
Updated On
</th>
<th scope="col">
Status
</th>
<th scope="col">
File
</th>
</tr>
</thead>
<tbody>
<ng-template [ngTemplateOutlet]="tmplt"></ng-template>
</tbody>
</table>
<div style="text-align:center">
<input type="button" (click)="AddColum()" class="btn btn-info" value="Add New">
<input type="submit" class="btn btn-primary" (click)="Save()" value="Save" />
<input type="button" class="btn btn-danger" value="Cancel">
</div>
</form>
</div>
<ng-template #tmplt>
<tr *ngFor="let kbase of Colum; let i =index" #sec>
<td>{{kbase.DocumentDetails.DocName}}</td>
<td>{{kbase.ModifiedBy}}</td>
<td>{{kbase.ModifiedDate}}</td>
<td>
<div class="form-group col-md-8">
<select name="select" class="form-control" [(ngModel)]="kbase.IsStatus">
<option value="true">Active</option>
<option value="false">In Active</option>
</select>
</div>
</td>
<td>
<app-file-upload [documentModel]="kbase.DocumentDetails" [isMultipleFile]="true" [model]="kbase" (emitterFile)="fileSelect($event)"></app-file-upload>
</td>
<td>
<input class="btn btn-danger" type="button" value="Remove" (click)="Delete(kbase.DocumentDetails.Id)" />
</td>
</tr>
</ng-template>
TS File:
import { Component, OnInit, ViewChild, TemplateRef } from '#angular/core';
import { FormControl, Validators } from '#angular/forms';
import { knowledgebaseModal } from '../Model/knowledgebase.model';
import { DocumentDetails } from '../Model/document.model';
import { KnowledgeBaseService } from '../Service/knowledgebase.service';
#Component
({
selector: 'knowledgebase',
templateUrl: './app/QadAdminConfig/Templates/knowledgebase.component.html',
providers: []
})
export class KnowledgeBaseComponet implements OnInit {
docArray: DocumentDetails[] = [];
kbase: knowledgebaseModal;
isFile = false;
result: any;
data: any;
Colum: Array<knowledgebaseModal> = [];
#ViewChild("tmplt") tmpltTbl: TemplateRef<any>;
constructor(private _knowledgebaseService: KnowledgeBaseService) {
}
ngOnInit() {
this.getFile();
}
fileSelect(knowledgemodal: knowledgebaseModal) {
this.Colum.forEach(x => {
if (JSON.stringify(x) == JSON.stringify(knowledgemodal))
x = knowledgemodal;
});
}
AddColum() {
let model: knowledgebaseModal = new knowledgebaseModal();
model.DocumentDetails = new DocumentDetails();
model.DocumentDetails.Id = 0;
this.Colum.push(model);
}
Save() {
this._knowledgebaseService.Save(this.Colum).subscribe(x => {
if (x.Success == true) {
this.result = x;
}
this.getFile();
});
}
getFile() {
this._knowledgebaseService.GetFileContent().subscribe(
data => {
if (data.Success) {
this.Colum = data.Result;
console.log(this.Colum);
}
});
}
Delete(sec: number) {
if (sec != -1) {
this.Colum.splice(sec, 1);
// need to check the document id
this._knowledgebaseService.Delete(10118).subscribe(x => {
this.result = x;
});
console.log(sec);
}
}
}
Actually you are passing your Document details Id to the Delete method you have declared, not the index of array that's why you are not getting the correct results.
Try to replace your code with this in Html
<input class="btn btn-danger" type="button" value="Remove" (click)="Delete(i, kbase.DocumentDetails.Id)" />
And in TS
Delete(deletedIndex: number, docId: number) {
if (deletedIndex != -1) {
this.Colum.splice(deletedIndex, 1);
this._knowledgebaseService.Delete(docId).subscribe(x => {
this.result = x;
});
console.log(deletedIndex);
}
}
NB: You should delete the item from view(DOM) after getting successful delete response from your service.

AngularJS custom filter for highlight text

I create a filter on a table. Here the code:
<table id="tableText" class="table table-hover table-striped" ng-init="allNews()">
<tr>
<td colspan="5">
<input type="text" placeholder="Ricerca testo" class="form-control" ng-model="inputText">
</td>
</tr>
<tr>
<th>Titolo</th>
<th>Text</th>
<th>Disattivato</th>
<th>Modifica</th>
<th ng-if="!cancelDelete">Elimina</th>
<th ng-if="cancelDelete">Annulla</th>
</tr>
<tr ng-repeat="news in allNews | filter : inputText">
<td>
<div ng-hide="editingData[news.id]"><span ng-bind-html="news | deleteTitle"></span></div>
<div ng-show="editingData[news.id]"><input type="text" class="form-control" ng-model="news.title" /></div>
</td>
<td>
<div ng-hide="editingData[news.id]"><span ng-bind-html="news | deleteText"></span></div>
<div ng-show="editingData[news.id]"><input type="text" class="form-control" ng-model="news.arg" /></div>
</td>
<td>
<div ng-hide="editingData[news.id]"><input type="checkbox" disabled ng-model="news.isDeleted"></div>
<div ng-show="editingData[news.id]"><input type="checkbox" ng-model="news.isDeleted"></div>
</td>
<td>
<div ng-hide="editingData[news.id]"><button id="modify" class="btn btn-primary" ng-click="modify(news, $event)">Modifica</button></div>
<div ng-show="editingData[news.id]"><button id="accept" class="btn btn-success" ng-click="update(news)">Accetta</button></div>
</td>
<td>
<div ng-hide="editingData[news.id]"><button id="delete" class="btn btn-danger" ng-click="delete(news.id)">Cancella</button></div>
<div ng-show="editingData[news.id]"><button id="cancel" class="btn btn-danger" ng-click="cancelModify()">Annulla</button></div>
</td>
</tr>
</table>
The entry on the table is read from db:
$scope.allNews = function () {
var url = '/data_db.asmx/GetAllNews';
var obj = {};
$http.post(url, obj)
.success(
function (response) {
if (response.Error) {
console.log('Server error');
}
else {
$scope.allNews = response.d;
}
})
.error(
function (response) {
console.log('Unkwnow error.');
});
}
I'd like to highlight the text that is search in the 1st row of the table. For now, i receive this error:
angular.js:13920 Error: [filter:notarray] Expected array but received: function ()
but the filter works.
Your problem is that $scope.allNews is a function. When you use it in ng-repeat directive and the directive is evaluated for the first time, your angular will try to examine the allNews property of your $scope as an array.
When the function gets called the first time (which might never happen when angular first encouters the error), it woul overwrite the allNews property with the resulting array of your $http POST request.
Rename either the function or the property and bind your ng-repeat to the array it recieves (and maybe initialize it with an empty array until it is populated by the $http result).
Something like:
$scope.allNews = [];
$scope.getAllNews = function() {
var url = '/data_db.asmx/GetAllNews';
var obj = {};
$http.post(url, obj)
.success(
function (response) {
if (response.Error) {
console.log('Server error');
}
else {
$scope.allNews = response.d;
}
})
.error(
function (response) {
console.log('Unkwnow error.');
});
}
Alternatively try using ngResource, create a service and inject that into your controller. Then populate the array by accessing the service.

How to use radio buttons in ReactJS?

I am new to ReactJS, sorry if this sounds off. I have a component that creates several table rows according to the received data.
Each cell within the column has a radio checkbox. Hence the user can select one site_name and one address from the existing rows. The selection shall be shown in the footer. And thats where I am stuck.
var SearchResult = React.createClass({
render: function () {
var resultRows = this.props.data.map(function (result) {
return (
<tbody>
<tr>
<td>
<input type="radio" name="site_name" value={result.SITE_NAME}>
{result.SITE_NAME}
</input>
</td>
<td>
<input type="radio" name="address" value={result.ADDRESS}>
{result.ADDRESS}
</input>
</td>
</tr>
</tbody>
);
});
return (
<table className="table">
<thead>
<tr>
<th>Name</th>
<th>Address</th>
</tr>
</thead>
{resultRows}
<tfoot>
<tr>
<td>chosen site name ???? </td>
<td>chosen address ????? </td>
</tr>
</tfoot>
</table>
);
},
});
In jQuery I could do something like $("input[name=site_name]:checked").val() to get the selection of one radio checkbox type and insert it into the first footer cell.
But surely there must be a Reactjs way, which I am totally missing? Many Thanks
Any changes to the rendering should be change via the state or props (react doc).
So here I register the event of the input, and then change the state, which will then trigger the render to show on the footer.
var SearchResult = React.createClass({
getInitialState: function () {
return {
site: '',
address: '',
};
},
onSiteChanged: function (e) {
this.setState({
site: e.currentTarget.value,
});
},
onAddressChanged: function (e) {
this.setState({
address: e.currentTarget.value,
});
},
render: function () {
var resultRows = this.props.data.map(function (result) {
return (
<tbody>
<tr>
<td>
<input
type="radio"
name="site_name"
value={result.SITE_NAME}
checked={this.state.site === result.SITE_NAME}
onChange={this.onSiteChanged}
/>
{result.SITE_NAME}
</td>
<td>
<input
type="radio"
name="address"
value={result.ADDRESS}
checked={this.state.address === result.ADDRESS}
onChange={this.onAddressChanged}
/>
{result.ADDRESS}
</td>
</tr>
</tbody>
);
}, this);
return (
<table className="table">
<thead>
<tr>
<th>Name</th>
<th>Address</th>
</tr>
</thead>
{resultRows}
<tfoot>
<tr>
<td>chosen site name {this.state.site} </td>
<td>chosen address {this.state.address} </td>
</tr>
</tfoot>
</table>
);
},
});
jsbin
Here is the simplest way of implementing radio buttons in react js.
class App extends React.Component {
setGender(event) {
console.log(event.target.value);
}
render() {
return (
<div onChange={this.setGender.bind(this)}>
<input type="radio" value="MALE" name="gender"/> Male
<input type="radio" value="FEMALE" name="gender"/> Female
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
Edited
You can use arrow function instead of binding. Replace the above code as
<div onChange={event => this.setGender(event)}>
For a default value use defaultChecked, like this
<input type="radio" value="MALE" defaultChecked name="gender"/> Male
Based on what React Docs say:
Handling Multiple Inputs.
When you need to handle multiple controlled input elements, you can add a name attribute to each element and let the handler function choose what to do based on the value of event.target.name.
For example:
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>
);
}
}
Link to example: https://codesandbox.io/s/6l6v9p0qkr
At first, none of the radio buttons is selected so this.state is an empty object, but whenever the radio button is selected this.state gets a new property with the name of the input and its value. It eases then to check whether user selected any radio-button like:
const isSelected = this.state.platform ? true : false;
EDIT:
With version 16.7-alpha of React there is a proposal for something called hooks which will let you do this kind of stuff easier:
In the example below there are two groups of radio-buttons in a functional component. Still, they have controlled inputs:
function App() {
const [platformValue, plaftormInputProps] = useRadioButtons("platform");
const [genderValue, genderInputProps] = useRadioButtons("gender");
return (
<div>
<form>
<fieldset>
Windows
<input
value="windows"
checked={platformValue === "windows"}
{...plaftormInputProps}
/>
Mac
<input
value="mac"
checked={platformValue === "mac"}
{...plaftormInputProps}
/>
Linux
<input
value="linux"
checked={platformValue === "linux"}
{...plaftormInputProps}
/>
</fieldset>
<fieldset>
Male
<input
value="male"
checked={genderValue === "male"}
{...genderInputProps}
/>
Female
<input
value="female"
checked={genderValue === "female"}
{...genderInputProps}
/>
</fieldset>
</form>
</div>
);
}
function useRadioButtons(name) {
const [value, setState] = useState(null);
const handleChange = e => {
setState(e.target.value);
};
const inputProps = {
name,
type: "radio",
onChange: handleChange
};
return [value, inputProps];
}
Working example: https://codesandbox.io/s/6l6v9p0qkr
Make the radio component as dumb component and pass props to from parent.
import React from "react";
const Radiocomponent = ({ value, setGender }) => (
<div onChange={setGender.bind(this)}>
<input type="radio" value="MALE" name="gender" defaultChecked={value ==="MALE"} /> Male
<input type="radio" value="FEMALE" name="gender" defaultChecked={value ==="FEMALE"}/> Female
</div>
);
export default Radiocomponent;
It's easy to test as it is a dumb component (a pure function).
Just an idea here: when it comes to radio inputs in React, I usually render all of them in a different way that was mentionned in the previous answers.
If this could help anyone who needs to render plenty of radio buttons:
import React from "react"
import ReactDOM from "react-dom"
// This Component should obviously be a class if you want it to work ;)
const RadioInputs = (props) => {
/*
[[Label, associated value], ...]
*/
const inputs = [["Male", "M"], ["Female", "F"], ["Other", "O"]]
return (
<div>
{
inputs.map(([text, value], i) => (
<div key={ i }>
<input type="radio"
checked={ this.state.gender === value }
onChange={ /* You'll need an event function here */ }
value={ value } />
{ text }
</div>
))
}
</div>
)
}
ReactDOM.render(
<RadioInputs />,
document.getElementById("root")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
import React, { Component } from "react";
class RadionButtons extends Component {
constructor(props) {
super(props);
this.state = {
// gender : "" , // use this one if you don't wanna any default value for gender
gender: "male" // we are using this state to store the value of the radio button and also use to display the active radio button
};
this.handleRadioChange = this.handleRadioChange.bind(this); // we require access to the state of component so we have to bind our function
}
// this function is called whenever you change the radion button
handleRadioChange(event) {
// set the new value of checked radion button to state using setState function which is async funtion
this.setState({
gender: event.target.value
});
}
render() {
return (
<div>
<div check>
<input
type="radio"
value="male" // this is te value which will be picked up after radio button change
checked={this.state.gender === "male"} // when this is true it show the male radio button in checked
onChange={this.handleRadioChange} // whenever it changes from checked to uncheck or via-versa it goes to the handleRadioChange function
/>
<span
style={{ marginLeft: "5px" }} // inline style in reactjs
>Male</span>
</div>
<div check>
<input
type="radio"
value="female"
checked={this.state.gender === "female"}
onChange={this.handleRadioChange}
/>
<span style={{ marginLeft: "5px" }}>Female</span>
</div>
</div>
);
}
}
export default RadionButtons;
Here's what I have used. Hope this helps.
Defining variable first.
const [variableName, setVariableName] = useState("");
Then, we will need the actual radio buttons.
<input
type="radio"
name="variableName"
value="variableToCheck"
onChange={(e) =>
setVariableName("variableToCheck")
}
checked={variableName === "variableToCheck"}
/>
#Tomasz Mularczyk mentions react hooks in his answer, but I thought I'd put in a solution I recently used that uses just the useState hook.
function Radio() {
const [currentRadioValue, setCurrentRadioValue] = useState()
const handleRadioChange = (e) => {
setCurrentValue(e.target.value);
};
return (
<>
<div>
<input
id="radio-item-1"
name="radio-item-1"
type="radio"
value="radio-1"
onChange={handleRadioChange}
checked={currentRadioValue === 'radio-1'}
/>
<label htmlFor="radio-item-1">Radio Item 1</label>
</div>
<div>
<input
id="radio-item-2"
name="radio-item-2"
type="radio"
value="radio-2"
onChange={handleRadioChange}
checked={currentRadioValue === 'radio-2'}
/>
<label htmlFor="radio-item-2">
Radio Item 1
</label>
</div>
</>
);
}
Clicking a radio button should trigger an event that either:
calls setState, if you only want the selection knowledge to be local, or
calls a callback that has been passed in from above self.props.selectionChanged(...)
In the first case, the change is state will trigger a re-render and you can do
<td>chosen site name {this.state.chosenSiteName} </td>
in the second case, the source of the callback will update things to ensure that down the line, your SearchResult instance will have chosenSiteName and chosenAddress set in it's props.
I also got confused in radio, checkbox implementation. What we need is, listen change event of the radio, and then set the state. I have made small example of gender selection.
/*
* A simple React component
*/
class App extends React.Component {
constructor(params) {
super(params)
// initial gender state set from props
this.state = {
gender: this.props.gender
}
this.setGender = this.setGender.bind(this)
}
setGender(e) {
this.setState({
gender: e.target.value
})
}
render() {
const {gender} = this.state
return <div>
Gender:
<div>
<input type="radio" checked={gender == "male"}
onClick={this.setGender} value="male" /> Male
<input type="radio" checked={gender == "female"}
onClick={this.setGender} value="female" /> Female
</div>
{ "Select Gender: " } {gender}
</div>;
}
}
/*
* Render the above component into the div#app
*/
ReactDOM.render(<App gender="male" />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
To build upon ChinKang said for his answer, I have a more dry'er approach and in es6 for those interested:
class RadioExample extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedRadio: 'public'
};
}
handleRadioChange = (event) => {
this.setState({
selectedRadio: event.currentTarget.value
})
};
render() {
return (
<div className="radio-row">
<div className="input-row">
<input
type="radio"
name="public"
value="public"
checked={this.state.selectedRadio === 'public'}
onChange={this.handleRadioChange}
/>
<label htmlFor="public">Public</label>
</div>
<div className="input-row">
<input
type="radio"
name="private"
value="private"
checked={this.state.selectedRadio === 'private'}
onChange={this.handleRadioChange}
/>
<label htmlFor="private">Private</label>
</div>
</div>
)
}
}
except this one would have a default checked value.
Bootstrap guys, we do it like this:
export default function RadioButton({ onChange, option }) {
const handleChange = event => {
onChange(event.target.value)
}
return (
<>
<div className="custom-control custom-radio">
<input
type="radio"
id={ option.option }
name="customRadio"
className="custom-control-input"
onChange={ handleChange }
value = { option.id }
/>
<label
className="custom-control-label"
htmlFor={ option.option }
>
{ option.option }
</label>
</div>
</>
)
}
import React from 'react';
import './style.css';
export default function App() {
const [currentRadioValue, setCurrentValue] = React.useState('on');
const handleRadioChange = value => {
setCurrentValue(value);
};
return (
<div>
<>
<div>
<input
name="radio-item-1"
value="on"
type="radio"
onChange={e => setCurrentValue(e.target.value)}
defaultChecked={currentRadioValue === 'on'}
/>
<label htmlFor="radio-item-1">Radio Item 1</label>
{currentRadioValue === 'on' && <div>one</div>}
</div>
<div>
<input
name="radio-item-1"
value="off"
type="radio"
onChange={e => setCurrentValue(e.target.value)}
defaultChecked={currentRadioValue === 'off'}
/>
<label htmlFor="radio-item-2">Radio Item 2</label>
{currentRadioValue === 'off' && <div>two</div>}
</div>
</>
</div>
);
}
working example: https://stackblitz.com/edit/react-ovnv2b