ReactJS and disable/enable selected field - reactjs

I'm trying to have disabled/enabled selected input field for edits. So far I have it done for all fields at once as
constructor(props) {
super(props);
this.state = { disabled: true }
}
handleEdit() {
this.setState( {disabled: !this.state.disabled} )
}
render(){
return(
<div className="col-md-3"><label>First Name</label></div>
<div className="col-md-6">
<input
type="text"
className="form-control react-form-input"
id="fname"
name="fname"
disabled={(this.state.disabled)? "disabled" : ""}
/>
<i className="fas fa-edit" onClick = {this.handleEdit.bind(this)}></i>
</div>
</div>
<div className="col-md-3"><label>Last Name</label></div>
<div className="col-md-6">
<input
type="text"
className="form-control react-form-input"
id="lname"
name="lname"
disabled={(this.state.disabled)? "disabled" : ""}
/>
<i className="fas fa-edit" onClick = {this.handleEdit.bind(this)}></i>
</div>
)}
but then I want to edit only selected field based on the element ID. I have tried to switch it to handle as an event.target.id but that wasn't working at all.
Any tips on that matter?

You can store the editable states of each input in an object:
state = {
editable: {}
};
handleEdit = id => {
this.setState(({ editable }) => ({
editable: { ...editable, [id]: !editable[id] }
}));
};
render() {
return (
<div>
<div className="col-md-3">
<label>First Name</label>
</div>
<div className="col-md-6">
<input
type="text"
className="form-control react-form-input"
id="fname"
name="fname"
disabled={!this.state.editable.fname}
/>
<i className="fa fa-edit" onClick={() => this.handleEdit("fname")} />
</div>
<div className="col-md-3">
<label>Last Name</label>
</div>
<div className="col-md-6">
<input
type="text"
className="form-control react-form-input"
id="lname"
name="lname"
disabled={!this.state.editable.lname}
/>
<i className="fa fa-edit" onClick={() => this.handleEdit("lname")} />
</div>
</div>
);
}
Working Example:

You can create a component that encapsulates the editing state
function EditableField(props) {
const [editing, setEditing] = React.useState(false);
function toggleEditing() {
setEditing(currentState => !currentState);
}
return (
<div>
<label>{props.label}</label>
<input
value={props.value}
onChange={props.onChange}
disabled={props.disabled || !editing}
/>
<button onClick={toggleEditing}>
{editing ? 'Save' : 'Edit'}
</button>
</div>
)
}
Demo
function EditableField(props) {
const [editing, setEditing] = React.useState(false);
function toggleEditing() {
setEditing(currentState => !currentState);
}
return (
<div>
<label>{props.label}</label>
<input
value={props.value}
onChange={props.onChange}
disabled={props.disabled || !editing}
/>
<button onClick={toggleEditing}>
{editing ? 'Save' : 'Edit'}
</button>
</div>
)
}
EditableField.defaultProps = {
editing: false,
disabled: false
}
function App() {
return (
<div>
<EditableField label="FirstName"/>
<EditableField label="LastName"/>
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>

I have came up with working solution for my code based on #trixn suggestion:
constructor(props) {
super(props);
this.state = { }
}
handleEdit(id) {
let setEdit = this.state[id];
this.setState( {[id]: !setEdit});
}
render(){
return(
<div className="col-md-3"><label>First Name</label></div>
<div className="col-md-6">
<input
type="text"
className="form-control react-form-input"
id="fname"
name="fname"
disabled={!this.state.fname}
/>
<i className="fas fa-edit" onClick = {() => this.handleEdit('fname')}></i>
</div>
</div>
<div className="col-md-3"><label>Last Name</label></div>
<div className="col-md-6">
<input
type="text"
className="form-control react-form-input"
id="lname"
name="lname"
disabled={!this.state.lname}
/>
<i className="fas fa-edit" onClick = {() => this.handleEdit('lname')}></i>
</div>
)}

Related

How can I put the correct ID in my model?

I have an API where I want to put a template for each book in order to edit it on the same page.
Unfortunately, it always shows me the last data in the list and not the data I want.
What I actually want is when I press the PUT button for "id 2", I want my model to show me the data for "id 2" and not the last id from the database (for example, "id 10").
Here is my constructor and my call from my api :
constructor(props) {
super(props)
this.state = {
data: [],
openPost: false,
openPut: false
}
}
componentDidMount() {
axios.get('https://127.0.0.1:8000/api/books')
.then(response => {
this.setState({
data: response.data
})
})
}
Here is my code:
{
data.map(book =>
<div key={book.id}>
<div className="card ml-auto mr-auto mb-3">
<div className="card-body" key={book.id}>
<h2 className="card-title">{book.title}</h2>
<h6 className="card-subtitle mb-2 text-muted">{book.subtitle}</h6>
<p className="card-text">{book.content}</p>
<Model id={"Model_put-" + book.id} value={book.id} trigger={this.state.openPut} setTrigger={!this.state.openPut} id_book={book.id}>
<button onClick={() => this.setState({ openPut: false })} className="close-btn btn-danger">X</button>
<h3>My Model</h3>
<p>This is my button triggered Model</p>
<input type="text" name="id" className='form-control' value={book.id} ></input>
<div className="row">
<div className="col">
<input type="text" name="title" className='form-control' placeholder='Title' ></input>
</div>
<div className="col">
<input type="text" name="content" className='form-control' placeholder="Content" ></input>
</div>
</div>
<div className="col">
<textarea className='form-control mt-2' defaultValue={book.content} />
</div>
</Model>
<button onClick={() => this.setState({ openPut: true })} type="button" className="btn btn-warning" id={"book-" + book.id} href="#">
PUT
</button>
</div>
</div>
</div>)
}
And the contents of my Modal.js file:
return (this.props.trigger) ? (
<div className="modal">
<div className="modal-inner">
{ this.props.children }
</div>
</div>
) : ""
Thanks in advance !
Every one one your modals is looking at the same openPut variable, which is a boolean, so they are either all open, or all closed. It just so happens that the last one is the only visible one. Quickest fix is:
<Model
id={"Model_put-" + book.id}
value={book.id}
trigger={this.state.openPut === book.id}
setTrigger={!this.state.openPut} id_book={book.id}
>
/* ... */
</Model>
<button
onClick={() => this.setState({ openPut: book.id })}
type="button"
className="btn btn-warning"
id={"book-" + book.id}
href="#"
>
PUT
</button>

Reactjs - how can i take input from one component(inputbox) and use it in other component

I am building a MOVIE Search API app and I am taking input from one serah input box from the user with help of following code
import React, { Component } from "react";
import styles from "../styles/Example.module.css";
import Appletv from "../appletv.json";
import Link from 'next/link';
export default class example extends Component {
constructor(props) {
super(props);
this.state = {
movies: "",
filteredShows: Appletv.shows, // Starting with all shows
};
}
handMoviesChange = (event) => {
this.setState({
movies: event.target.value,
});
};
handleSubmit = (event) => {
event.preventDefault();
const newFilteredShows = Appletv.shows.filter((show) => {
return (
this.state.movies === "" ||
show.Title.toLowerCase().includes(this.state.movies.toLowerCase())
);
});
this.setState({ filteredShows: newFilteredShows });
};
render() {
console.table(Appletv.shows);
return (
<div className={styles.container}>
<h3 className={styles.Title}>SearchTest</h3>
<form onSubmit={this.handleSubmit}>
<div className={styles.row}>
<input
className={styles.input}
id="search"
type="input"
required
placeholder="Please enter title"
value={this.state.movies}
onChange={this.handMoviesChange}
/>
</div>
<Link href="/searchtest">
<button className={styles.button} type="submit">
Search
</button>
</Link>
</form>
<div className={styles.results} >
{this.state.filteredShows.map((filteredShows, index) => {
return (
<div>
{/* <h1 className={styles.title}>{filteredShows.Title}</h1>
<img
className={styles.image}
src={filteredShows.Thumbnail}
alt="Thumbnail"
/>
<h5 className={styles.genre}>
{filteredShows.Genre} & {filteredShows["Release date"]}
</h5>
<p className={styles.desc}>{filteredShows.Description}</p> */}
</div>
);
})}
</div>
</div>
);
}
}
Output of this code is following
and I want to get those results in the second component and second component code is following
import React, { Component, useState } from "react";
import styles from "../styles/Home.module.css";
import Appletv from "../appletv.json";
import Pagination from "./components/Pagination";
/* import Netflixlogo from "../logos/netflix.png";
*//* import Appletvlogo from "../logos/appletv.png";
import dstvlogo from "../logos/dstv.png";
import Amzonlogo from "../logos/amzon.png";
import Showmaxlogo from "../logos/showmax.png"; */
export default class searchtest extends Component {
constructor(props) {
super(props);
this.state = {
movies: "",
filteredShows: Appletv.shows, // Starting with all shows
};
}
handMoviesChange = (event) => {
this.setState({
movies: event.target.value,
});
};
handleSubmit = (event) => {
event.preventDefault();
/* const filteredShows = array.slice(0, 6);
*/
const newFilteredShows = Appletv.shows.filter((show) => {
return (
this.state.movies === "" ||
show.Title.toLowerCase().includes(this.state.movies.toLowerCase())
);
});
this.setState({ filteredShows: newFilteredShows });
};
render() {
console.table(Appletv.shows);
return (
<div className={styles.container}>
{/* <h3 className={styles.Title}>SearchTest</h3>
*/}
{/* <h4 className={styles.searche}>Search Results</h4>
*/}{" "}
<input
className={styles.searchin}
id="search"
type="input"
required
placeholder="Please enter title"
value={this.state.movies}
onChange={this.handMoviesChange}
/>{" "}
<button className={styles.searchbtn} type="submit">
Search
</button>{" "}
<div className={styles.row}>
<form onSubmit={this.handleSubmit}>
<div className={styles.row}>
<h4>Filtering Options</h4>
<label className={styles.label}>Movies</label>
<input
id="name"
className={styles.checkbox}
type="checkbox"
required
/>
</div>
<div className={styles.row}>
<label className={styles.label}>TV Show</label>
<input id="name" className={styles.checkbox} type="checkbox" />
</div>
<hr className={styles.hr} />
{/* <div className={styles.row}>
<input
className={styles.input}
id="search"
type="input"
required
placeholder="Please enter title"
value={this.state.movies}
onChange={this.handMoviesChange}
/>
</div>
<div className={styles.row}>
<input
className={styles.input}
type="text"
list="genre"
placeholder="Please Choose Genre"
/>
<datalist id="genre">
<option className={styles.option}>scifi</option>
<option>Documentry</option>
</datalist>
</div>
<div className={styles.row}>
<input
className={styles.input}
id="name"
type="input"
placeholder="Season Input"
/>
</div> */}
<div className={styles.row}>
<label className={styles.label}>Netflix</label>
<input className={styles.checkbox} id="name" type="checkbox" />
</div>
<div className={styles.row}>
<label className={styles.label}>Amazon Prime</label>
<input className={styles.checkbox} id="name" type="checkbox" />
</div>
<div className={styles.row}>
<label className={styles.label}>Apple TV+</label>
<input
className={styles.checkbox}
id="name"
type="checkbox"
required
/>
</div>
<div className={styles.row}>
<label className={styles.label}>Showmax</label>
<input
className={styles.checkbox}
id="name"
type="checkbox"
required
/>
</div>
<div className={styles.row}>
<label className={styles.label}>DSTV</label>
<input
className={styles.checkbox}
id="name"
type="checkbox"
required
/>
</div>
<hr className={styles.hr} />
<label for="cars" className={styles.label}>
Select Year
</label>
<div className={styles.row}>
<select
name="cars"
id="cars"
data-toggle="dropdown"
className={styles.dropdown}
>
{/* <option value=""></option>
*/} <option value="2015">2015</option>
<option value="2016">2016</option>
<option value="2017">2017</option>
<option value="2018">2018</option>
<option value="2019">2019</option>
<option value="2020">2020</option>
<option value="2021">2021</option>
</select>
</div>
<label for="cars" className={styles.label}>
Select Genre
</label>
<div className={styles.row}>
<select
name="cars"
id="cars"
data-toggle="dropdown"
className={styles.dropdown}
>
{/* <option value=""></option>
*/} <option value="SCIFI">SCIFI</option>
<option value="comedy">COMEDY</option>
<option value="ADVENTURE">ADVENTURE</option>
<option value="DOCUMENTRY">DOCUMENTRY</option>
</select>
</div>
<label for="cars" className={styles.label}>
Select Age Restriction
</label>
<div className={styles.row}>
<select
name="cars"
id="cars"
data-toggle="dropdown"
className={styles.dropdown}
>
{/* <option value=""></option>
*/} <option value="SCIFI">18+</option>
<option value="comedy">Adult</option>
<option value="ADVENTURE">Kids</option>
<option value="DOCUMENTRY">Cartoons</option>
</select>
</div>
<button className={styles.button} type="submit">
Apply Filters
</button>
</form>
</div>
<div className={styles.results}>
{/* here we are going to do conditional rendering like if netflix checkbox clicked then show or else not */}
{/* <img className={styles.condimg}
src={""}
alt="condren"
/> */}
<h4 className={styles.h2}>Search Results for {this.state.title}</h4>
{this.state.filteredShows.slice(0,4).map((filteredShows, index) => {
return (
<div>
<h1 className={styles.title}>{filteredShows.Title}</h1>
<img
className={styles.image}
src={filteredShows.Thumbnail}
alt="Thumbnail"
/>
<h5 className={styles.genre}>
{filteredShows.Genre} & {filteredShows["Release date"]}
</h5>
<p className={styles.desc}>{filteredShows.Description}</p>
</div>
);
})}
</div>
<Pagination/>
</div>
);
}
}
and output of the second component is like this
and can anyone help me for getting data from the first component to another second component I know we can do it with help of props and I am not getting how can I do that can anyone help me with this.
you can pass state through React router
<Link
to={{
pathname: '/pathname',
state: { results: 'this is results' }
}}
/>
In the component you can access the variable like this:
componentDidMount: function() {
var results= this.props.location.state.results
},
hope it help :D
You can add a prop (function) onUpdate to your search component, then call this function when you submit your search. On the parent-component, you can then add logic to pass it to your other component. For example, you add it to a state, which is then passed to your second component.
handMoviesChange = (event) => {
this.setState({
movies: event.target.value,
});
this.props.onUpdate(event.target.value);
};
Then in your parent component:
<example onUpdate={(movies) => setState({ movies })} />
<searchtest movies={this.state.movies} />
Hope it helps.

Unsuccessful Rerender of Nested Component with JEST/Enzyme React Testing

I have a Parent component, App, and a nested component, SearchByForm. SearchByForm contains a radio buttons' group and I am attempting to modifying the third button's value to become checked (true). It can be identified by its className, .workstationRadioBtn.
SearchByForm Class
import React from 'react';
class SearchByForm extends React.Component {
constructor(props) {
super(props);
this.state = { which: 'order' };
}
buttonChange = (e) => {
if (e.target.checked) {
this.setState({ which: e.target.value });
this.props.updateFromSearchByForm(e.target.value);
}
}
render() {
return (
<form className="SearchByForm">
<div className="form-check">
<label>
<input
type="radio"
name="searchBy"
value="order"
checked={this.state.which === 'order'}
onChange={this.buttonChange}
className="orderRadioBtn"
/>
Order
</label>
</div>
<div className="form-check">
<label>
<input
type="radio"
name="searchBy"
value="employee"
checked={this.state.which === 'employee'}
onChange={this.buttonChange}
className="employeeRadioBtn"
/>
Employee
</label>
</div>
<div className="form-check">
<label>
<input
type="radio"
name="searchBy"
value="workstation"
checked={this.state.which === 'workstation'}
onChange={this.buttonChange}
className="workstationRadioBtn"
/>
Work Station
</label>
</div>
</form>
);
}
}
export default SearchByForm;
Search Component class:
class Search extends React.Component {
constructor(props) {
super(props);
this.state = { searchKey: '_id', searchBy: 'order', searchResults: null };
this.updateFromSearchByForm = this.updateFromSearchByForm.bind(this);
this.updateFromKeysForm = this.updateFromKeysForm.bind(this);
this.clearSearchResults = this.clearSearchResults.bind(this);
this.populateSearchResults = this.populateSearchResults.bind(this);
}
updateFromSearchByForm(value) {
this.setState({ searchBy: value });
}
updateFromKeysForm(value) {
this.setState({ searchKey: value });
}
keyToSearchBy = () => {
switch (this.state.searchBy) {
case 'order':
return (
<KeysForm which='order' updateFromKeysForm={this.updateFromKeysForm}></KeysForm>
);
case 'employee':
return (
<KeysForm which='employee' updateFromKeysForm={this.updateFromKeysForm}></KeysForm>
);
case 'workstation':
return (
<KeysForm which='workstation' updateFromKeysForm={this.updateFromKeysForm}></KeysForm>
);
default:
return (
<KeysForm which='order' updateFromKeysForm={this.updateFromKeysForm}></KeysForm>
);
}
}
clearSearchResults = () => {
this.setState({ searchResults: null });
}
populateSearchResults = (results) => {
this.setState({ searchResults: results });
}
displayOrderResults = () => {
let list = [];
let count = 0;
list.push(<label> Orders found that match your search criteria:</label>)
for (let result of this.state.searchResults) {
list.push(
<ListGroupItem key={count}>ID: {result._id}, OrderID: {result.OrderID}, CustomerID: {result.CustomerID}, DateRequired: {result.DateRequired}, Status: {result.Status}, PriorityFlag: {result.PriorityFlag}</ListGroupItem>
)
count++;
}
return list;
}
displayEmployeeResults = () => {
let list = [];
let count = 0;
list.push(<label> Employees found that match your search criteria:</label>)
for (let result of this.state.searchResults) {
list.push(
<ListGroupItem key={count}>ID: {result._id}, Staff Name: {result.WorkerName}</ListGroupItem>
)
count++;
}
return list;
}
displayWorkStationResults = () => {
let list = [];
let count = 0;
list.push(<label> Stations found that match your search criteria:</label>)
for (let result of this.state.searchResults) {
list.push(
<ListGroupItem key={count}>ID: {result._id}, Work Station Name: {result.StationName}</ListGroupItem>
)
count++;
}
return list;
}
showSearchResults = () => {
//Know how to display based on searchBy type.
switch (this.state.searchBy) {
case 'order':
return (this.displayOrderResults());
case 'employee':
return (this.displayEmployeeResults());
case 'workstation':
return (this.displayWorkStationResults());
default:
break;
}
for (let result of this.state.searchResults) {
console.log(result);
}
}
render() {
return (
<Jumbotron>
<div className="App">
<div className='header'>
<div className='header-space1'>
<div className='button-header'>
<Link to='/menu'>
<Button id='menu'>Back to Menu</Button>
</Link>
</div>
</div>
<div className='header-space2'>
<h2>Search</h2>
</div>
<div className='header-space3'>
<div className='button-header'>
</div>
</div>
</div>
<div className='Search'>
<div className='Row'>
<div className='SearchForm'>
<p>What would you like to search by?</p>
<SearchByForm updateFromSearchByForm={this.updateFromSearchByForm}></SearchByForm>
{this.keyToSearchBy()}
</div>
</div>
<ValueForm searchKey={this.state.searchKey} searchBy={this.state.searchBy} clearSearchResults={this.clearSearchResults} populateSearchResults={this.populateSearchResults}></ValueForm>
<br></br>
<div className='Row'>
<div className='SearchResults'>
<p>Search Results</p>
{this.state.searchResults ?
<ListGroup>
{this.showSearchResults()}
</ListGroup>
:
null}
</div>
</div>
</div>
</div>
</Jumbotron>
);
}
}
The test currently creates a full tree copy and successfully checks the .workstationRadioBtn's checked value to true. It also successfully changes the 'which' state field of SearchByForm to 'workstation'.
My test's current state is as follows
describe('Work Station Search', () => {
it(' successfully selects order radio button', () => {
const wrapper = mount(
<Router>
<Search />
</Router>
);
console.log(wrapper.debug());
const wrapperSearchByForm = wrapper.find(SearchByForm);
wrapperSearchByForm.find('input').filter('.workstationRadioBtn').simulate('change', {target: {checked: true}});
wrapperSearchByForm.setState({ which: 'workstation' });
wrapper.update();
console.log(wrapper.debug());
})
});
The debug code of the test shows the above to be true, however the update() doesn't appear to have successfully rerendered the second nested component, KeysForm, whose returned render is dependent upon the SearchByForm. It is still acting as though the Order radio button is checked.
Here is the test's full debug output:
console.log src/__tests__/Search/Search.test.js:84
<BrowserRouter>
<Router history={{...}}>
<Search>
<Jumbotron fluid={false}>
<div className="jumbotron">
<div className="App">
<div className="header">
<div className="header-space1">
<div className="button-header">
<Link to="/menu">
<LinkAnchor href="/menu" navigate={[Function: navigate]}>
<a href="/menu" onClick={[Function: onClick]}>
<Button id="menu" variant="primary" active={false} disabled={false} type="button">
<button id="menu" disabled={false} type="button" className="btn btn-primary">
Back to Menu
</button>
</Button>
</a>
</LinkAnchor>
</Link>
</div>
</div>
<div className="header-space2">
<h2>
Search
</h2>
</div>
<div className="header-space3">
<div className="button-header" />
</div>
</div>
<div className="Search">
<div className="Row">
<div className="SearchForm">
<p>
What would you like to search by?
</p>
<SearchByForm updateFromSearchByForm={[Function: bound updateFromSearchByForm]}>
<form className="SearchByForm">
<div className="form-check">
<label>
<input type="radio" name="searchBy" value="order" checked={true} onChange={[Function]} className="orderRadioBtn" />
Order
</label>
</div>
<div className="form-check">
<label>
<input type="radio" name="searchBy" value="employee" checked={false} onChange={[Function]} className="employeeRadioBtn" />
Employee
</label>
</div>
<div className="form-check">
<label>
<input type="radio" name="searchBy" value="workstation" checked={false} onChange={[Function]} className="workstationRadioBtn" />
Work Station
</label>
</div>
</form>
</SearchByForm>
<KeysForm which="order" updateFromKeysForm={[Function: bound updateFromKeysForm]}>
<div className="KeysForm">
<div className="OrderKeys">
<p>
Which Order Key would you like to search by?
</p>
<form>
<div className="form-check">
<label>
<input type="radio" name="orderKey" value="_id" checked={true} onChange={[Function]} className="form-check-input" />
Id
</label>
</div>
<div className="form-check">
<label>
<input type="radio" name="orderKey" value="DateRequired" checked={false} onChange={[Function]} className="form-check-input" />
Date Required
</label>
</div>
<div className="form-check">
<label>
<input type="radio" name="orderKey" value="Status" checked={false} onChange={[Function]} className="form-check-input" />
Status
</label>
</div>
<div className="form-check">
<label>
<input type="radio" name="orderKey" value="PriorityFlag" checked={false} onChange={[Function]} className="form-check-input" />
Priority Flag
</label>
</div>
</form>
</div>
</div>
</KeysForm>
</div>
</div>
<ValueForm searchKey="_id" searchBy="order" clearSearchResults={[Function: bound ]} populateSearchResults={[Function: bound ]}>
<form className="ValueForm">
<label>
<input type="text" name="value" value="" onChange={[Function]} />
</label>
<Button onClick={[Function]} variant="primary" active={false} disabled={false} type="button">
<button onClick={[Function]} disabled={false} type="button" className="btn btn-primary">
Search
</button>
</Button>
</form>
</ValueForm>
<br />
<div className="Row">
<div className="SearchResults">
<p>
Search Results
</p>
</div>
</div>
</div>
</div>
</div>
</Jumbotron>
</Search>
</Router>
</BrowserRouter>

How to set value of an input from Redux store, but then still be able to write in that input and update value?

My input is also like a searchbox: I want to be able to search for names on the input but then I want to be able to click a name from the dropdown search results and set the input with that value. I then want to be able to search again if I want to change that value.
Tried using DefaultValue and uncontrolled components, but neither worked. Not sure if I used them right though.
class PublishTest extends Component {
constructor() {
super();
this.state = {
showRows: false,
numberOfRows: ["row"],
search: "",
searchResults: [],
insightListActive: false,
insightTagsActive: false
};
this.hideOrShowRows = this.hideOrShowRows.bind(this);
this.addNewRow = this.addNewRow.bind(this);
this.searchAllUsers = this.searchAllUsers.bind(this);
this.onChangeInsight = this.onChangeInsight.bind(this);
this.clearInput = this.clearInput.bind(this);
this.clearInsightList = this.clearInsightList.bind(this);
this.searchInsightTags = this.searchInsightTags.bind(this);
this.clearTagList = this.clearTagList.bind(this);
}
componentDidMount() {
this.props.getLoginCredential();
this.props.getAllRoles();
}
hideOrShowRows() {
this.setState({
showRows: !this.state.showRows
});
}
addNewRow() {
this.setState({
numberOfRows: [...this.state.numberOfRows, "row"]
});
}
searchAllUsers(e) {
this.setState({
search: e.target.value
});
const searchOption = this.state.search;
fetch("http://localhost:3500/soiapi/", {
method: "POST",
headers: {
"content-type": "application/json"
},
body: JSON.stringify({
data: [
{
name: "searchUser",
urlparameter: { search: searchOption, appId: "1" },
parameter: ""
}
]
})
})
.then(res => res.json())
.then(data => {
this.setState({
searchResults: data[0]
});
});
}
onChangeInsight = e => {
this.props.insightOnChangeValue(e.target.value);
this.props.searchInsights(e.target.value);
this.setState({
insightListActive: true
});
};
clearInput() {
this.setState({
search: "",
searchResults: []
});
}
clearInsightList() {
this.setState({
insightListActive: false
});
}
searchInsightTags(e) {
this.props.getInsightTags(e.target.value);
this.setState({
insightTagsActive: true
});
}
clearTagList() {
this.setState({
insightTagsActive: false
});
}
render() {
const { searchResults } = this.state;
let rows;
let button;
let icon;
if (this.state.showRows) {
rows = this.state.numberOfRows.map((row, i) => (
<div>
<Row index={i} />
</div>
));
button = (
<button
onClick={this.addNewRow}
className="Button--secondary float-right"
>
Add Row
</button>
);
icon = (
<i aria-hidden="true" className="Icon Icon--minus-small iconFont"></i>
);
} else if (!this.state.showRows) {
icon = (
<i aria-hidden="true" className="Icon Icon--plus-small iconFont"></i>
);
}
if (this.props.user.userDTO) {
const { userDTO } = this.props.user;
const insightSearchResults = this.props.insightReducerValue
.insightList[0];
return (
<div style={{ padding: "5px" }} className="publish-container">
<h4 className="publish-h4">Publish Insights</h4>
<h6 className="publish-h6">Insight Details</h6>
<hr className="line-style" />
<section id="publish-section-1">
<div class="Grid">
<div class="Col Col--3">
<div class="grid-block">
<div className="Form-group publish-insights-input">
<label className="Form-label insight-label">
Insight Name <span className="asterisk">*</span>:
</label>
<div id="insight-container">
<input
type="text"
placeholder="Insight Name"
onChange={this.onChangeInsight}
onFocus={this.clearInsightList}
onBlur={this.clearInsightList}
className="Form-input"
value={this.props.insightReducerValue.insightValue}
/>
{this.state.insightListActive ? (
<InsightList insights={insightSearchResults} />
) : null}
</div>
</div>
</div>
</div>
<div class="Col Col--3">
<div class="grid-block">
<div class="Form-group publish-insights-input">
<label class="Form-label">
Insight Source <span className="asterisk">*</span>:
</label>
<select
id="insight-source"
role="combobox"
class="Form-input"
>
<option
disabled="disabled"
selected="selected"
aria-disabled="true"
>
Choose one
</option>
<option>Tableau</option>
<option>Qlik</option>
<option>D3JS</option>
<option>CXI</option>
</select>
</div>
</div>
</div>
</div>
</section>
<section id="publish-section-2">
<div class="Grid">
<div class="Col Col--6">
<div class="grid-block">
<div className="Form-group publish-insights-input">
<label class="Form-label">
URL <span className="asterisk">*</span>:
</label>
<input type="text" placeholder="URL" class="Form-input" />
</div>
</div>
</div>
</div>
</section>
<section id="publish-section-3">
<div class="Grid">
<div class="Col Col--6">
<div class="grid-block">
<div className="publish-insights-input">
<label class="Form-label">
Description <span className="asterisk">*</span>:
</label>
<textarea
placeholder="Description"
class="Form-input"
></textarea>
</div>
</div>
</div>
</div>
</section>
<section id="publish-section-4">
<div class="Grid">
<div class="Col Col--3">
<div class="grid-block">
<div className="Form-group publish-insights-input">
<label className="Form-label third-div-p">
POC Name <span className="asterisk">*</span>:
</label>
<input
type="text"
placeholder="Name"
className="Form-input"
value={`${userDTO.firstName} ${userDTO.lastName}`}
/>
</div>
</div>
</div>
<div class="Col Col--3">
<div class="grid-block">
<div className="Form-group publish-insights-input">
<label className="Form-label third-div-p">
Group Distro (E-mail Address)
<span className="asterisk">*</span>:
</label>
<input
type="text"
placeholder="Email"
class="Form-input"
value={userDTO.emailAddress}
/>
</div>
</div>
</div>
</div>
</section>
<section id="publish-section-5">
<div class="Grid">
<div class="Col Col--6">
<div class="grid-block">
<div class="Form-group publish-insights-input">
<div class="Form-checkbox is-restricted">
<input
id="restricted"
name="checkboxDefault"
type="checkbox"
/>
<label for="restricted">Is Restricted</label>
</div>
</div>
</div>
</div>
</div>
</section>
<section id="publish-section-6">
<div class="Grid">
<div class="Col Col--2">
<div class="grid-block">
<div id="tree-section">
<label id="category-label" className="Form-label">
Category <span className="asterisk">*</span>
</label>
<div id="tree-container">
<PublishInsightsTree />
</div>
</div>
</div>
</div>
<div class="Col Col--4">
<div class="grid-block">
<div className="Form-group publish-insights-input">
<label className="Form-label third-div-p">
Add Insight Tags <span className="asterisk">*</span>:
</label>
<input
type="text"
onChange={e => this.searchInsightTags(e)}
onFocus={this.clearTagList}
onBlur={this.clearTagList}
placeholder="Write some insight tags"
className="Form-input"
/>
</div>
{
this.state.insightTagsActive ?
<div>
{
this.props.insightTags ?
<InsightTags tags={this.props.insightTags[0]} />
: null
}
</div>
: null
}
</div>
<div class="grid-block">
<div class="Grid">
<div class="Col Col--7 img-url-input">
<div class="grid-block">
<div
id="file-div"
class="Form-group publish-insights-input"
>
<label class="Form-label">
Image URL <span className="asterisk">*</span>:
</label>
<input
type="text"
placeholder="Insight Name"
class="Form-input"
/>
</div>
</div>
</div>
<div class="Col Col--5">
<div class="grid-block">
<button class="Button--secondary upload-image-button">
Upload Image
</button>
</div>
</div>
<div class="Col Col--7 url-description">
<div class="grid-block">
<p>
Please copy paste the generated URL after uploading
image file.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<section id="publish-section-7">
<h6 className="publish-h6">Role Details</h6>
<hr className="line-style" />
</section>
<section id="publish-section-8">
<div class="Grid">
<div class="Col Col--2">
<div class="grid-block">
<label id="roles-label" className="Form-label">
Assign to Role <span className="asterisk">*</span>
</label>
<div id="all-roles">
{this.props.listOfRoles ? (
<ListOfRoles roles={this.props.listOfRoles} />
) : null}
</div>
</div>
</div>
<div class="Col Col--4">
<div class="grid-block assign-user-div">
<label className="Form-label label-spacing">
Assign to Individual User:
</label>
<div className="Form-group">
<textarea
onChange={this.searchAllUsers}
type="text"
placeholder="Look up by EID/Name"
onFocus={this.clearInput}
onBlur={this.clearInput}
className="Form-input assign-user-textarea"
value={this.state.search}
></textarea>
{searchResults.length > 0 ? (
<div id="user-list">
{searchResults ? (
<UserList searchResults={this.state.searchResults} />
) : null}
</div>
) : null}
</div>
</div>
</div>
</div>
</section>
<section id="publish-section-9">
<h6 className="publish-h6 metadata-heading" onClick={this.hideOrShowRows}>
<span id="metadata-icon">{icon}</span>
Metadata Info
</h6>
<hr className="line-style color" />
</section>
<section id="publish-section-10">
<div class="Grid">
<div class="Col Col--12 add-row-col">
<div class="grid-block">{button}</div>
</div>
</div>
{rows}
</section>
</div>
);
} else {
return null;
}
}
}
const mapStateToProps = state => ({
user: state.LoginReducer.loginInfo,
searchUser: state.LoginReducer.searchUser,
insightReducerValue: state.SideDrawerReducer,
listOfRoles: state.LoginReducer.listOfRoles,
insightTags: state.SideDrawerReducer.insightTags
});
export default connect(
mapStateToProps,
{
getLoginCredential,
searchUser,
insightOnChangeValue,
searchInsights,
getAllRoles,
getInsightTags
}
)(PublishTest);
This is the part of the code I need help with:
<input
type="text"
placeholder="Insight Name"
onChange={this.onChangeInsight}
onFocus={this.clearInsightList}
onBlur={this.clearInsightList}
className="Form-input"
value={this.props.insightReducerValue.insightValue}
/>
{this.state.insightListActive ? (
<InsightList insights={insightSearchResults} />
) : null}
Since your code is a little messy, I made a sandbox that fetches some data from a dummy API, stores that data to our local component state. We have a text field where we can type in usernames and a list of matching usernames will appear as a dummy drop, clicking any one of those usernames will set the value in the text field. It's pretty straight forward will give you an idea on how to get started.
EDIT:
Sandbox Link: https://codesandbox.io/s/eloquent-pascal-pf3hd?fontsize=14
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends React.Component {
state = {
input: "",
users: [],
dropdown: []
};
async componentDidMount() {
let users = await fetch("https://jsonplaceholder.typicode.com/users");
users = await users.json();
this.setState({ users });
}
handleChange = e => {
this.setState({ input: e.target.value }, () => {
let results = this.state.users.filter(user => {
return user.username.indexOf(this.state.input) > -1;
});
this.setState({ dropdown: results });
});
};
handleSelect = username => e => {
this.setState({ input: username }, () => this.setState({ dropdown: [] }));
};
render() {
return (
<div className="App">
<h1>Search</h1>
<input
type="text"
name="input"
onChange={this.handleChange}
value={this.state.input}
/>
{this.state.dropdown.map(d => (
<h3 onClick={this.handleSelect(d.username)} key={d.id}>
{d.username}
</h3>
))}
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Could you start off by loading all possible search results into state or props (e.g. under this.props.searchResults)? Then you could try using the datalist tag. Not quite sure if this was what you were going for, but it looked like something like that could work for you.
<input type="text"
defaultValue={this.props.insightReducerValue.insightValue}
list="inputOptions"
onChange={(e) => console.log("Current input field value: ", e.target.value)} />
<datalist id="inputOptions">
{this.props.searchResults.map((item, key) =>
<option key={key} value={item} />
)}
</datalist>
P.S. Check the supported browsers list under the link.

How to add multiple checkboxes to a state

How to save multiple checkboxes to a single state and add each checkbox to its previous state?
These are my states:
Operators : '',
TypeStatus : '',
RegistrationStatus : '',
This is my function:
changeHandle = (event) => {
this.setState({
[event.target.name]: event.target.value
});
};
This is my input:
I want to click on each of these checkboxes to add the value to the state
and add the RegisterButtonsActivated class to its parent label
<div className="container-fluid">
<div className="row flex-row-reverse">
<div className="col" data-toggle="buttons">
<label className="RegisterButtons">
<input
type="checkbox"
name="Operators"
id="MCI"
value="MCI"
checked={this.state.operations}
onChange={this.changeHandle}
onClick={this.props.handleFilterOperatorMCI}
/>
همراه اول
</label>
</div>
<div className="col" data-toggle="buttons">
<label className="RegisterButtons">
<input
type="checkbox"
name="Operators"
id="irancell"
value="irancell"
checked={true}
onChange={this.changeHandle}
onClick={this.props.handleFilterOperatorIrancell}
/>
ایرانسل
</label>
</div>
<div className="col" data-toggle="buttons">
<label className="RegisterButtons">
<input
type="checkbox"
name="Operators"
id="rightel"
value="rightel"
checked={this.state.operations}
onChange={this.changeHandle}
onClick={this.handleFilterOperatorRightel}
/>
رایتل
</label>
</div>
</div>
<div className="row justify-content-center">
<div className="col">
<hr className="hr-Filterbox" />
</div>
</div>
<div className="row flex-row-reverse">
<div className="col">
<label className={`RegisterButtons ${this.state.TypeStatus ===
"Justice" ? 'RegisterButtonsActivated' : ''}`}>
<input
type="checkbox"
name="TypeStatus"
id="Justice"
value="Justice"
onChange={this.changeHandle}
onClick={this.props.handleFilterTypeJustice}
/>
دائمی
</label>
</div>
<div className="col">
<label className={`RegisterButtons ${this.state.TypeStatus ===
"Credit" ? 'RegisterButtonsActivated' : ''}`}>
<input
type="checkbox"
name="TypeStatus"
id="Credit"
value="Credit"
onChange={this.changeHandle}
onClick={this.props.handleFilterTypeCredit}
/>
اعتباری
</label>
</div>
</div>
<div className="row justify-content-center">
<div className="col">
<hr className="hr-Filterbox" />
</div>
</div>
<div className="row flex-row-reverse">
<div className="col" data-toggle="buttons">
<label className={`RegisterButtons ${this.state.OperatingStatus
=== "New" ? 'RegisterButtonsActivated' : ''}`}>
<input
type="checkbox"
name="OperatingStatus"
id="New"
value="New"
onChange={this.changeHandle}
onClick={this.props.handleFilterWorkStatusNew}
/>
صفر
</label>
</div>
<div className="col" data-toggle="buttons">
<label className={`RegisterButtons ${this.state.OperatingStatus
=== "LowPerformance" ? 'RegisterButtonsActivated' : ''}`}>
<input
type="checkbox"
name="OperatingStatus"
id="LowPerformance"
value="LowPerformance"
onChange={this.changeHandle}
onClick={this.props.handleFilterWorkStatusOld}
/>
کم کارکرد
</label>
</div>
<div className="col" data-toggle="buttons">
<label className={`RegisterButtons ${this.state.OperatingStatus
=== "Old" ? 'RegisterButtonsActivated' : ''}`}>
<input
type="checkbox"
name="OperatingStatus"
id="Old"
value="Old"
onChange={this.changeHandle}
onClick={this.props.handleFilterWorkStatusLowPerformance}
/>
کارکرده
</label>
</div>
</div>
</div>
I want to click on each of these checkboxes to add the value to the state and add the RegisterButtonsActivated class to its parent label
You can do like this.....
this.state = {
checkboxes: {
Operators: null,
TypeStatus: null,
RegistrationStatus: null,
}
}
Below will handle the change in existing state and if you will pass new checkbox it will add new key to the state object.
changeHandle = (event) => {
this.setState((prevState) => ({
checkboxes: {...prevState.checkboxes, [event.target.name]: event.target.value }
}))
};
You can do this with your state;
this.state = {
checkboxes: {
Operators: {
currentValue: null,
previousValues:[]
},
TypeStatus: {
currentValue: null,
previousValues:[]
},
RegistrationStatus: {
currentValue: null,
previousValues:[]
},
}
}
Now your handler will look something like this;
changeHandle = (event) => {
const checkboxes = this.state.checkboxes;
checkboxes[event.target.name].currentValue = event.target.value;
checkboxes[event.target.name].previousValues.push(event.target.value); // last element will be the latest value.
this.setState({
checkboxes
});
};

Resources