I am creating a React Js website. Where I have a form with 2 select fields Min price and Max price. I want to apply validation on these two fields. So if user click minimum price of500 the maximum should only display 500 going up. My react component code is available below.
import React, { Component } from 'react';
import { Form, FormGroup, Input } from 'reactstrap';
class MyForm extends Component {
constructor(props) {
super(props);
this.state = {
};
}
handleSearch(event) {
alert("Search button clicked");
event.preventDefault();
}
render() {
return (
<div>
<header className="headerbg d-flex">
<div className="container my-auto">
<div className="row">
<div className="offset-1 col-10 offset-lg-0 col-lg-4">
<div id="search-form-div" className="container">
<div className="row">
<div className="col-12 my-4">
<h3>Search</h3>
<Form onSubmit={this.handleSearch}>
<FormGroup>
<Input type="select" name="select3" id="select3">
<option selected disabled>Min Price</option>
<option value="0">0</option>
<option value="500">500</option>
<option value="1000">1000</option>
<option value="1500">1500</option>
<option value="2000">2000</option>
</Input>
</FormGroup>
<FormGroup>
<Input type="select" name="select4" id="select4">
<option selected disabled>Max Price</option>
<option value="0">0</option>
<option value="500">500</option>
<option value="1000">1000</option>
<option value="1500">1500</option>
<option value="2000">2000</option>
</Input>
</FormGroup>
<FormGroup>
<Input type="submit" name="search" id="search" className="btn btn-primary" value="Search" />
</FormGroup>
</Form>
</div>
</div>
</div>
</div>
</div>
</div>
</header>
</div>
);
}
}
export default MyForm;
Hope you understand my code. Thanks in advance.
The recommended way (and might I add, the cleaner way, is to place to option values in an array, which you commit to state and change whenever a value is changed). So your component might look something like this...
import React, { Component } from 'react';
import { Form, FormGroup, Input } from 'reactstrap';
const defaultValues = [
{ value: 0, text: 0, key: 1 },
{ value: 500, text: 500, key: 2 },
{ value: 1000, text: 1000, key: 3 },
{ value: 1500, text: 1500, key: 4 },
{ value: 2000, text: 2000, key: 5 }
];
const MIN_TITLE = { selected: true, disabled: true, text: 'Min Price' };
const MAX_TITLE = { selected: true, disabled: true, text: 'Max Price' };
class MyForm extends Component {
constructor(props) {
super(props);
this.state = {
minData: [MIN_TITLE, ...defaultValues],
maxData: [MAX_TITLE, ...defaultValues],
minValue: null,
maxValue: null
};
// This allows us to access the state inside the renderoptions function.
// Another way (if you want to ignore this line) is to write the renderOptions
// as renderOptions = data => {}
this.renderOptions = this.renderOptions.bind(this);
}
handleSearch(event) {
alert('Search button clicked');
event.preventDefault();
}
renderOptions(data) {
return data.map(datum => {
// this allows us to indicate whether we are selecting or disabling
const selected = datum.selected || false;
const disabled = datum.disabled || false;
return (
<option key={datum.key} value={datum.value} selected={selected} disabled={disabled}>
{datum.text}
</option>
);
});
}
// Writing your function so does not require the binding in the constructor
handleMinSelect = event => {
const value = event.target.value;
const newMaxValues = [];
defaultValues.forEach(datum => {
// I'm under the impression that reactstrap will change the value to string
if (datum.value >= Number.parseInt(value, 10)) {
newMaxValues.push(datum);
}
});
this.setState({
maxData: [MAX_TITLE, ...newMaxValues],
minValue: value
});
};
handleMaxSelect = event => {
const value = event.target.value;
this.setState({ maxValue: value });
};
render() {
// I'm stri
<div>
<header className="headerbg d-flex">
<div className="container my-auto">
<div className="row">
<div className="offset-1 col-10 offset-lg-0 col-lg-4">
<div id="search-form-div" className="container">
<div className="row">
<div className="col-12 my-4">
<h3>Search</h3>
<Form onSubmit={this.handleSearch}>
<FormGroup>
<Input
type="select"
name="select3"
id="select3"
value={this.state.minValue}
onChange={this.handleMinSelect}>
{this.renderOptions(this.state.minData)}
</Input>
</FormGroup>
<FormGroup>
<Input
type="select"
name="select4"
id="select4"
value={this.state.maxValue}
onChange={this.handleMaxSelect}>
{this.renderOptions(this.state.maxData)}
</Input>
</FormGroup>
<FormGroup>
<Input
type="submit"
name="search"
id="search"
className="btn btn-primary"
value="Search"
/>
</FormGroup>
</Form>
</div>
</div>
</div>
</div>
</div>
</div>
</header>
</div>;
}
}
export default MyForm;
Basically, the major changes are
Set the values in state and render them using the renderOptions
When a new state pops up, change the value and update the maxData property
Hope it helps you out 😉
you need to add an onChange function to your Inputs. Then update the state when the minValue input is selected. When this is the max, compare the selected value with the minValue in the state and reject it when less than the
I would do another logic if had to do this kind of form anyway. I would create the option list for maxValue dynamicaly based on the choice for minValue. I would display only the values greater than the min. I guess this is more convenient for user.
Related
I am new to Reactjs and trying to implement cascading dropdowns so that when user select state he will be able to get corresponding cities in next dropdown.
Expected result : For state: Maharashtra -> Cities : Nagpur, Pune
This is my code
enter code here
import React from "react";
import { useState } from "react";
import "./Form.css";
import states from "./city-state";
function Form() {
const stateList = states;
let citiesList = [];
const [cities, setcities] = useState([]);
const [stateName, setStateName] = useState(states[0].state);
const [cityName, setCityName] = useState();
const getCities = (e) => {
console.log("state:" + e.target.value);
for (let i = 0; i < stateList.length; i++) {
if (stateList[i].state == "" + e.target.value)
citiesList = stateList[i].cities;
}
console.log("cityList:" + citiesList);
setcities(citiesList)
setStateName(e.target.value);
setCityName(citiesList[0].districts)
}
const refreshCityName = (e) =>{
setCityName(e.target.value);
}
return (
<div>
<section className="part cos-form">
<div className="boxx01">
<h2 className="h2-awards">FILL THE FORM</h2>
<h3 className="h3-awards">we will call you back</h3>
</div>
<form className="boxx02" onSubmit={handleSubmit}>
<div className="bpart1">
<input
type="text"
name="firstname"
placeholder="Name"
autoComplete="off"
onChange={handleChange}
/>{" "}
<p>{formErrors.username}</p>
<input
type="text"
name="email"
placeholder="Email"
autoComplete="off"
onChange={handleChange}
/>
<p>{formErrors.email}</p>
<input
type="tel"
name="mobileno"
placeholder="Mobile No."
autoComplete="off"
maxLength={10}
onChange={handleChange}
/>
<p>{formErrors.mobile}</p>
<span className="policy">
By clicking on Submit, I allow Lakmé Academy Powered by Aptech{" "}
<br /> to contact me, and use & share my personal data as per
the <br />
<a href="/privacy-policy" target="_blank" title="Privacy Policy">
Privacy Policy.
</a>
</span>
</div>
<div className="bpart2">
<select name="b_course_id">
<option selected="selected" value="">
Select Course Interested in
</option>
<option value="385">Short Term Courses</option>
<option value="414">Make-up</option>
<option value="468">Cosmetology</option>
<option value="527">Nail Art</option>
<option value="542">Hair</option>
<option value="559">Salon Management</option>
<option value="563">Beauty Therapy/Skin</option>
</select>
<select name="stateList" onChange={getCities}>
{stateList.map((e,key)=>{
return(
<option key ={key} value={e.state}>
{e.state}
</option>
)
})}
</select>
<select name="CityList" onChange={refreshCityName}>
{cities.map((e,key)=>{
return(
<option key ={key} value={e.name}>
{e.name}
</option>
)
})}
</select>
<button
disabled=""
className="black_btn btn"
name="student_enquiry_form_submit"
id="student_enquiry_form_submit"
type="button"
>
Submit
</button>
</div>
</form>
</section>
</div>
);
}
export default Form;
This is my structure of data in city-state.json. In this file, I have states names and districts name only.
{
"states": [
{
"state": "Andhra Pradesh",
"districts": [
"Anantapur",
"Chittoor"
]
}
}
please help me
I am using adminlte HTML theme, I converted this theme into reactjs, everything is working fine except select2(Multi-select)
onselect I am trying to trigger the handler that is userIdHandler but it does not trigger
There is two cases:
user name with multi-select : userIdHandler not working
Status with single select: userIdHandler working
please help me to trigger userIdHandler from multi-select also
import React, { useEffect, useState } from "react";
import { getTeam } from "../services/ApiCall/attendanceApiCall";
export default function TeamattendanceComponent() {
const [team, setTeam] = useState([]);
const userIdHandler = (e) => {
console.log("hi", e.target.value);
};
useEffect(() => {
const script = document.createElement("script");
script.src = "myjs/content.js";
script.async = true;
document.body.appendChild(script);
getTeam().then((res) => {
console.log(res.data);
setTeam(res.data);
});
}, []);
return (
<div className="content-wrapper">
{/* Content Header (Page header) */}
<div className="card">
<div className="card-body row">
<div className="col-4">
<div className="form-group ">
<label>User Name</label>
<select
id
className="form-control select2"
multiple="multiple"
data-placeholder="Select a State"
style={{ width: "100%" }}
onChange={userIdHandler}
>
{team.map((user, key) => {
console.log("team data", team);
return (
<option key={key} value={user._id}>
{user.name}
</option>
);
})}
</select>
</div>
</div>
<div className="col-4">
<div className="form-group">
<label>Status</label>
<select id className="form-control" onChange={userIdHandler}>
<option>Select</option>
<option>ON</option>
<option>OFF</option>
</select>
</div>
</div>
<div className="col-4">
<div className="form-group">
<label className="hidden-xs"> </label>
<input
type="submit"
className="btn btn-primary form-control"
defaultValue="Filter"
/>
</div>
</div>
</div>
</div>
{/* /.content */}
</div>
);
}
I'm afraid that you are not using a Select2 elements that's a regular select.
First install react-select: npm i --save react-select
This is how you define a multiselect on Select2:
import Select from 'react-select';
const options = [{label: "option 1", value: 1}, {label: "option 2", value: 2}];
<Select
isMulti
options={options}
onChange={userIdHandler}
/>
And then change your userIdHandler` function to this:
const userIdHandler = (value) => {
console.log(value);
};
This way it should print you the label and value selected.
I'm working on react and I have several drop-down and text fields where I want to clear/reset selected values from the select options and from the text field when I click the clear button. I've tried some logic, but it doesn't work. can someone help me? I created a function called "handleReset" but it does nothing and doesn't show an error.
Here is my code:
import React, { useState, useEffect } from "react";
import {
Button,
Container,
} from "react-bootstrap";
import { CarAction } from "../../Store/Actions/CarAction";
import { useDispatch, useSelector } from "react-redux";
const CarRequests = () => {
const dispatch = useDispatch();
const getCarMake = useSelector((state) => state.CarReducer.car);
const getCarMileage = useSelector((state) => state.CarReducer.mileage);
const getCarTrim = useSelector((state) => state.CarReducer.trim);
let [value, setValue] = useState()
let handleChange = (e) => {
setValue(e.target.value)
}
const handleReset = (e) => {
setValue(e.target.value = "");
}
useEffect(() => {
dispatch(CarAction.CarMake());
dispatch(CarAction.CarMileage());
dispatch(CarAction.CarTrim());
}, [dispatch]);
return (
<div className="flex-row align-items-center section">
<h3>
Filters
<i className="fa fa-cog icon float-right"></i>
</h3>
<Container className="box-shadow p-4">
<div className="form-row">
<div className="form-group col-lg-3">
<label>Make:</label>
<select className="custom-select" onChange={handleChange}>
<option value=''>Please select...</option>
{getCarMake.map((data, key) => <option value={data.value} key={key}>{data.name}</option>)}
</select>
</div>
<div className="form-group col-md-3">
<label>Model:</label>
<select className="custom-select">
<option value=''>Please select...</option>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
</select>
</div>
<div className="form-group col-md-3">
<label>Year:</label>
<select className="custom-select">
<option value=''>Please select...</option>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
</select>
</div>
<div className="form-group col-md-3">
<label>Mileage:</label>
<select className="custom-select" onChange={handleChange}>
<option value=''>Please select...</option>
{getCarMileage.map((data, key) => <option value={data.value} key={key}>{data.name}</option>)}
</select>
</div>
</div>
<div className="form-row">
<div className="form-group col-md-3">
<label>Car Trim:</label>
<select className="custom-select" onChange={handleChange}>
<option value=''>Please select...</option>
{getCarTrim.map((data, key) => <option value={data.value} key={key}>{data.name}</option>)}
</select>
</div>
<div className="form-group col-md-3">
<label>Email:</label>
<input type="email" placeholder="Email" className="custom-select" />
</div>
<div className="form-group col-md-3">
<label>Phone no:</label>
<input type="number" placeholder="Phone no" className="custom-select" />
</div>
</div>
<div className="container-buttons">
<Button className="mr-4" variant="light">
Search
</Button>
<Button variant="dark" onClick={handleReset}>Clear</Button>
</div>
</Container>
</div>
);
};
export default CarRequests;
The thing you are doing wrong is in handleReset function you are taking the event and you are setting the target value to empty which is ideally wrong.
In order to correct it we need to understand how the flow is working, you are using handleChange function in order to set the values to your state.
So in order to reset it you need to reset the value of the state only.
So the code becomes like this:
const handleReset = () => {
setValue("");
}
Now this will reset the value of your state variable and also use your state variable in your select method which will resolve the problem.
<select value={value}>
<option></option>
.
.
</select>
To make dynamic field working:
function App() {
const [value, setValue] = useState({});
const arr = ["hello", "cra"];
const arr2 = [
{
name: "hello",
id: "1",
},
{
name: "test2",
id: "2",
},
];
const handleChange = ({ target: { value: val, name } }) => {
setValue({ ...value, [name]: val });
};
const resetValue = () => {
setValue({});
};
console.log(value);
return (
<div id="wrapper">
<select
name="select1"
value={value.select1 || ""}
onChange={handleChange}
>
<option value=""></option>
{arr.map((val) => {
return <option value={val}>{val}</option>;
})}
</select>
<select
name="select2"
value={value.select2 || ""}
onChange={handleChange}
>
<option value=""></option>
{arr2.map(({ name, id }) => {
return <option value={id}>{name}</option>;
})}
</select>
<button onClick={resetValue}>Reset</button>
</div>
);
}
Or else you can initialise the value in your state as well like this
const [value, setValue] = useState({select1: "" , select2: ""});
which could further be used dynamically in your select tag for name attributes.
function App() {
const [value, setValue] = useState({ select1: "", select2: "" });
const arr = ["hello", "cra"];
const arr2 = [
{
name: "hello",
id: "1",
},
{
name: "test2",
id: "2",
},
];
const handleChange = ({ target: { value: val, name } }) => {
setValue({ ...value, [name]: val });
};
const resetValue = () => {
setValue({
select1: "",
select2: "",
});
};
console.log(value);
return (
<div id="wrapper">
<select name="select1" value={value.select1} onChange={handleChange}>
<option value=""></option>
{arr.map((val) => {
return <option value={val}>{val}</option>;
})}
</select>
<select name="select2" value={value.select2} onChange={handleChange}>
<option value=""></option>
{arr2.map(({ name, id }) => {
return <option value={id}>{name}</option>;
})}
</select>
<button onClick={resetValue}>Reset</button>
</div>
);
}
Seems you are trying to store multiple values in the value . don't use the word value there. I have tried to change it to [formValue, setFormValue]
Change 1:
let [formValue, setFormValue] = useState({
textfield1: '',
dropdownfield2: ''});
Change 2 - for dropdown changed values:
const handlDropDownChange = (event, value) => {
setFormValue({
...formValue,
['dropdownfield2']: value,
});
}
Change 3 - for mapping dropdown values from state, also use this to map to dropdown value:
formValue.dropdownfield2
Change 4 - for text field changes:
onChange={e => {
updateFieldMyForm(e);
}}
const updateFieldMyForm= e => {
setFormValue({
...formValue,
[e.target.name]: e.target.value
});
};
Note this will work for all text fields - just make sure that the name of this textfield matches the name used in the useState statement like - textfield1
Change 5 - to reset the whole thing at the end/submission
EDIT - 1
const handleReset = () => { setFormValue({ textfield1: "", dropdownfield2: "" }); };
Spread operator is the key in steps 2 & 4 [triple dots - ...] - let me know if you still have challenges.
I am new to react js and I am trying to get input value and set it to another html element (p)
And other thing is, I find it really hard to leran react js with all these complex syntaxes and things related to react js, are there any good tutorials that I can understand?
This is what I have been trying by researching all over the internet and I cannot go beyond this simple thing... Using jquery i could have done this so easily, and react js seems so complex to get the job done for some reason (maybe I am wrong). Anyway,
This is my SelectTrainsAndTickets.jsx
"use strict";
import React, { Component } from "react";
import { render } from "react-dom";
import "bootstrap/dist/css/bootstrap.css";
class SelectTrainsAndTickets extends Component {
constructor(props) {
super(props);
this.state={
noOfTickets: {document.getElementById('tickets')} //getting user input value
};
}
showDetails() {
this.setState({
noOfTickets:
});
console.log(this.state.noOfTickets);
}
render() {
return (
<React.Fragment>
<div className="container">
<div className="row">
<div className="col-md-2" />
<div className="col-md-4">
<select id="train" name="train" className="form-control">
<option value="select" disabled="disabled">
- Select Train -
</option>
<option value="1">Train A</option>
<option value="2">Train B</option>
<option value="3">Train C</option>
<option value="4">Train D</option>
</select>
</div>
<div className="col-md-4">
<input id="tickets"
className="form-control"
type="number"
placeholder="Number of tickets"
/>
</div>
<div className="col-md-2" />
</div>
<br />
<div className="row">
<div className="col-md-2" />
<div className="col-md-4" />
<div className="col-md-4 text-right">
<button
onClick={this.showDetails.bind(this)}
type="button"
className="btn btn-primary"
>
Buy Tickets
</button>
</div>
<div className="col-md-2">
<p>{this.state.noOfTickets}</p> //showing user input value
</div>
</div>
</div>
</React.Fragment>
);
}
}
export default SelectTrainsAndTickets;
Can someone tell me how to do this?
What you want to read up on is controlled inputs.
https://shripadk.github.io/react/docs/forms.html
There are only a few scenarios where you want to access the DOM directly and you almost never want to do it in your constructor as you are in your example.
First initialize your state you dont even need a constructor in this case.
class SelectTrainsandTIckets extends Component {
state = { ticketCount : 0, showTicketCount: false }
}
Since this is a controlled input you need to handle any change on that input. With events you get passed an event object where you can retrieve whatever the user is entering in your input. You want to store that change in the state variable you have setup.
handleChange(event){
this.setState({ticketCount : event.target.value})
}
Now you need to hook this all up to your actual input element in your render() method.
render() {
return(
<input name="myInput" onChange={handleChange.bind(this)} value={this.state.ticketCount} />
)
}
To display the current count you have already correctly displayed displayed the data but you want to hide the p element until the user clicks a button. Dont duplicate state especially for something like this. Simply hide the element until the user clicks a button.
<p style={this.state.showTicketCount ? {display: 'block'} : {display: 'none'}>{this.state.ticketCount}</p>
Finally the button to show the entered ticket count:
<button onClick={() => this.setState({showTicketCount: true})>Click me</button>
This is what I tried with help of the answers provided here. I got the idea and I changed it to the way I wanted it to work. This is my final answer:
"use strict";
import React, { Component } from "react";
import { render } from "react-dom";
import "bootstrap/dist/css/bootstrap.css";
class SelectTrainsAndTickets extends Component {
constructor(props) {
super(props);
this.state = {
noOfTickets: 0,
ticketCount: 0
};
this.haChange = this.haChange.bind(this);
this.getCount = this.getCount.bind(this);
}
haChange(event) {
this.setState({ noOfTickets: event.target.value });
}
getCount(){
this.setState({ticketCount: this.state.noOfTickets});
}
render() {
return (
<React.Fragment>
<div className="container">
<div className="row">
<div className="col-md-2" />
<div className="col-md-4">
<select id="train" name="train" className="form-control">
<option value="select" disabled="disabled">
- Select Train -
</option>
<option value="1">Train A</option>
<option value="2">Train B</option>
<option value="3">Train C</option>
<option value="4">Train D</option>
</select>
</div>
<div className="col-md-4">
<input onChange={this.haChange} className="form-control" type="number" placeholder="Number of tickets" />
</div>
<div className="col-md-2" />
</div>
<br />
<div className="row">
<div className="col-md-2" />
<div className="col-md-4" />
<div className="col-md-4 text-right">
<button onClick={this.getCount} type="button" value={this.state.ticketCount} className="btn btn-primary">
Buy Tickets
</button>
<p>{this.state.ticketCount === 0 ? '' : this.state.ticketCount}</p>
</div>
<div className="col-md-2" />
</div>
</div>
</React.Fragment>
);
}
}
export default SelectTrainsAndTickets;
--FieldSection.js--
import React, { Component } from 'react';
import Field from './Field.js';
class FieldSection extends Component{
constructor(props){
super(props);
this.state ={
numberOfFields: 1
}
}
addField = () => {
const { numberOfFields } = this.state;
this.setState({ numberOfFields: numberOfFields + 1 });
}
listFields = (numberOfFields) => {
var fields = [];
for(var i=0; i<numberOfFields; i++){
fields.push(
(<Field number={i} />)
)
}
return fields;
}
render () {
const {listFields, addField} = this;
const {numberOfFields} = this.state;
return (
<div>
<label><u>Fields</u></label>
{listFields(numberOfFields)}
<div id="fieldButtons">
<button id="addField" type="button" onClick={addField}> Add Field </button>
<button id="removeField" type="button"> Remove Field </button>
</div>
</div>
)
}
}
export default FieldSection;
-----------------Field.js-------------------
import React from 'react';
class Field extends React.Component {
constructor(props){
super(props);
this.state = {
value: 'empty',
specVisible: 'hidden',
display: 'none'
};
}
SelectChange = (event) => {
this.setState({value: event.target.value});
if(event.target.value === "string" )
{
this.setState({specVisible: 'visible'});
this.setState({display: 'block'});
}
else {
this.setState({specVisible: 'hidden'})
this.setState({display: 'none'})
}
}
render (){
const {SelectChange} = this;
const {value, specVisible, display} = this.state;
return (
<div>
<div>
<label><strong>New Field </strong></label>
<div id="remove-" className="remove" style={{display: "inline", visibility: "hidden"}}>
<label> --Remove </label> <input type="checkbox" id="removeBox" className="rmvCheckbox" />
<br />
</div>
<label> Name: </label>
<input id="name-" className="name" type="text" name="name" /> <br />
<label> Description: </label>
<input id="description-" className="description" name="description" /> <br />
<label> Datatype: </label>
<select value={value} onChange={SelectChange} id={`selectData-${this.props.number}`} className="selectData" name="selectData" /*onClick={AddListener}*/>
<option value="empty"> </option>
<option value="string"> String </option>
<option value="character"> Character </option>
<option value="timestamp"> Timestamp </option>
<option value="integer"> Integer </option>
<option value="long"> Long </option>
<option value="double"> Double </option>
<option value="boolean"> Boolean </option>
</select> <br />
</div>
<div id={`specifySection-${this.props.number}`} className="specifySection" style={{visibility: specVisible, display: display}} >
<label> Specify Length: </label>
<input className="specifyLength" type="text" name="length"/> <br />
</div>
</div>
)}
}
export default Field
I am trying to implement a feature where you click "Remove Field" button and a list of checkboxes next to all the new fields appears. Whenever you confirm the deletion, it would delete all the elements that are selected.
Obviously I could subtract one to the numberOfFields state, however I want to delete specific elements, rather than just the last field.
What would that look like?
You can do it as follows. The basic idea is to get all the ids of the fields that need to be deleted and iterate over them and delete all the components corresponding to these ids.
Sandbox for code
When addField is called fields state of FieldsSelection
component is updated by adding a key with unique id, with the Field
component as its value along with all the props.
The remove state tracks if remove Field has been clicked and
toggles the remove checkbox in each Field component by passing it
as a prop.
fieldsToRemove state is updated via the markFields prop in
Field component each time a remove field checkbox is clicked.
When deleteFields is called, it iterates over the fieldsToRemove
state and removes the corresponding components from the fields
state object.
I used uuid package for unique ids for each Field as opposed to deleting
via index, which is not a great way and also conflicts with the key prop of
react.
FieldSection.js
import React, { Component } from "react";
import Field from "./Field.js";
import { v4 } from "uuid";
class FieldSection extends Component {
constructor(props) {
super(props);
this.state = {
fields: {},
remove: false,
fieldsToRemove: []
};
}
addField = () => {
const fields = this.state.fields;
const id = v4();
fields[id] = <Field key={id} id={id} mark={this.markFields} />;
this.setState({ fields });
};
listFields = () => {
var ids = Object.keys(this.state.fields);
return ids.map(id => {
return React.cloneElement(this.state.fields[id], {
remove: this.state.remove
});
});
};
markFields = (checked, i) => {
if (checked) {
const arr = [...this.state.fieldsToRemove];
arr.push(i);
this.setState({ fieldsToRemove: arr });
} else {
const arr = this.state.fieldsToRemove.filter(x => i !== x);
this.setState({ fieldsToRemove: arr });
}
};
removeFields = () => {
this.setState({ remove: !this.state.remove });
};
deleteFields = () => {
const fields = { ...this.state.fields };
this.state.fieldsToRemove.forEach(id => {
delete fields[id];
});
this.setState({ fields, fieldsToRemove: [], remove: false });
};
render() {
const { listFields, addField, removeFields, deleteFields } = this;
const { numberOfFields, remove } = this.state;
return (
<div>
<label>
<u>Fields</u>
</label>
{listFields()}
<div id="fieldButtons">
<button id="addField" type="button" onClick={addField}>
{" "}
Add Field{" "}
</button>
<button id="removeField" type="button" onClick={removeFields}>
{" "}
Remove Field{" "}
</button>
<br />
<button type="button" onClick={deleteFields}>
{" "}
Delete Fields{" "}
</button>
</div>
</div>
);
}
}
export default FieldSection;
Field.js
import React from "react";
class Field extends React.Component {
constructor(props) {
super(props);
this.state = {
value: "empty",
specVisible: "hidden",
display: "none"
};
}
SelectChange = event => {
this.setState({ value: event.target.value });
if (event.target.value === "string") {
this.setState({ specVisible: "visible" });
this.setState({ display: "block" });
} else {
this.setState({ specVisible: "hidden" });
this.setState({ display: "none" });
}
};
render() {
const { SelectChange } = this;
const { value, specVisible, display } = this.state;
const styles = this.props.remove
? { display: "inline", visibility: "visible" }
: { display: "inline", visibility: "hidden" };
return (
<div>
<div>
<label>
<strong>New Field </strong>
</label>
<div id="remove-" className="remove" style={styles}>
<label> --Remove </label>{" "}
<input
type="checkbox"
id="removeBox"
className="rmvCheckbox"
onChange={e => {
this.props.mark(e.target.checked, this.props.id);
}}
/>
<br />
</div>
<label> Name: </label>
<input id="name-" className="name" type="text" name="name" /> <br />
<label> Description: </label>
<input
id="description-"
className="description"
name="description"
/>{" "}
<br />
<label> Datatype: </label>
<select
value={value}
onChange={SelectChange}
id={`selectData-${this.props.number}`}
className="selectData"
name="selectData" /*onClick={AddListener}*/
>
<option value="empty"> </option>
<option value="string"> String </option>
<option value="character"> Character </option>
<option value="timestamp"> Timestamp </option>
<option value="integer"> Integer </option>
<option value="long"> Long </option>
<option value="double"> Double </option>
<option value="boolean"> Boolean </option>
</select>{" "}
<br />
</div>
<div
id={`specifySection-${this.props.number}`}
className="specifySection"
style={{ visibility: specVisible, display: display }}
>
<label> Specify Length: </label>
<input className="specifyLength" type="text" name="length" /> <br />
</div>
</div>
);
}
}
export default Field;