onChange function on checkbox isn't working | ReactJS - reactjs

I'm learning ReactJS and today I can't resolve a difficulty, so I need your help.
I want to make a "Remember Me" for users that want to stay connected after reopening the website.
This is my code :
My function :
handleChangeCheckBox = (event) => {
console.log(event.target.checked)
this.setState({
isChecked: event.target.checked
})
}
When I call the function in the input checkbox field with an onChange :
<p>
<Input
type="checkbox"
name="rememberCheckbox"
className="rememberCheckbox"
id={this.state.isChecked}
onChange={this.handleChangeCheckBox}
/>
Remember Me
</p>
Nothing appears in my console when I click on the checkbox, so it seems like the calling function isn't working.

please try this. replace value with checked
<input type="checkbox"
name="rememberCheckbox"
checked={this.state.isChecked}
onChange={this.handleCheckBox}
/>

Code tested at given url
enter link description here
class App extends Component {
constructor(props) {
super(props);
this.state = { isChecked: false };
}
handleCheckBox = event => {
console.log(event.target.checked);
this.setState({
isChecked: event.target.checked
});
};
render() {
return (
<div>
<p>
<input
type="checkbox"
name="rememberCheckbox"
value={this.state.isChecked}
onChange={this.handleCheckBox}
/>
Remember Me
</p>
</div>
);
}
}

Welcome to Stack overflow!
Based on the code you shared, your function should be getting executed. I suspect you have an error somewhere else in your class rather than in those two code snippets you shared.
You can check this simple sandbox I made with a very barebones implementation like the one you have: https://codesandbox.io/s/react-simple-check-box-7etp4
One thing you're missing is using the checked html attribute rather than id. That's what will tell the checbox whether it's checked or not. It replaces the value attribute you use for input fields.
You also seem to be using an Input component. Try changing it for a normal HTML input instead.

it could be triggering twice.
if you are using create-react-app then your Appcomponent is wrapped in StrictMode like this:
<React.StrictMode>
<App />
</React.StrictMode>,
go to index.js and remove <React.StrictMode></React.StrictMode>
https://github.com/facebook/react/issues/12856#issuecomment-390206425

handleChangeCheckBox = () => { this.setState({ isChecked: ! this.state.isChecked }) }

Related

React: document.getElementById (or onClick) does not work

I want a random number to be generated and put into the "roomid" input field once the "generate" button is clicked, but the value shown is still 0 after I clicked the button. It guess it is not the problem of onClick because there was indeed a "?" added to the URL after I clicked the button. What is wrong with the code? Thank you so much for your help]1
React way of doing something like this would be
class StartStream extends Component {
state = { randomId: 0 }
generate = () => {
this.setState({ randomId: Math.random() * 1000 });
}
render() {
return <div>
<input type="text" value={this.state.randomId} />
<button onClick={this.generate}>Generate</button>
</div>;
}
}
Here is a working demo https://jsfiddle.net/tfc3javx/1/

Is there any public react function that gets executed every time state is changed just like render function?

I have a child component. It should create an object from props and render it. This object should get added as a state.
Below is the current code.
Example:-
<popupComponent element={object} />
popupComponent.js
class popupComponent extends Component {constructor(props) {
super(props);
this.state = {
name: ""
}
}
updateName (event) {
this.setState({
name: event.currentTarget.value
})
}
publishElement () {
this.props.saveAndClose({
name: this.state.name
});
this.setState({
name: ""
})
}
render() {
return (
<div draggable="true" >
<h4>Name:</h4>
<input id="elementName" type="text" placeholder="Enter element name" value={element.name} onChange={this.updateName.bind(this)}/>
<button id="saveAndClose" onClick={this.publishElement.bind(this)}>Save & close</button>
</div>
);
}
}
export default popupComponent;
Question: Which function other than render gets executed whenever state is changed? In this scenario constructor runs only once and I cannot try that because the time constructor gets executed, state isnt available.
Resolved issue by conditionally not creating the component at all.
Actual issue, Somehow this component's constructor was getting called only once but I wanted it getting called whenever it gets visually shown.
Resolved issue by conditionally not including the component at all as below.
{this.state.show ? <PopupMarkupEditor
element = {selectedElement}
saveAndClose = {this.saveElement}
show = {this.state.show}
/> : null }

google-maps-react infoWindow onChange issues

How to add a button in infowindow with google-maps-react?
Hello, I'm writing a React app, I was having an issue with changing state inside the InfoWindow from google-maps-react, the solution above helped me get through that hurdle.
Right now however, I'm having an issue with wanting to edit the content inside my InfoWindowEx component. Using the method above I am able to change the state of a text box inside the InfoWindowEx, however, when I click on the text box and I type it will let me type 1 letter and then I will have to click the text box again if I want to type the next letter, etc. I think this issue has to do with state.
I don't know if there is a solution to this, I have been trying a lot of different things, but hopefully someone can help me know what is going on.
Here is my InfoWindowEx component:
<InfoWindowEx
key={currentInfoWindow.id}
id={currentInfoWindow.id}
marker={this.state.activeMarker}
visible={this.state.showingInfoWindow}
selectedPlace={this.state.selectedPlace}
onInfoWindowClose={this.onInfoWindowClose}
>
<div >
{infoWindowEditBoxes}
{infoWindowContent}
</div>
</InfoWindowEx>
the Edit boxes are rendering in conditional statements here are they:
if (this.state.editButton) {
infoWindowEditBoxes = (
<div>
<input key={this.props.marker} id="editedName" type="text" placeholder="New Bathroom Name" onChange={this.handleTextBoxState}></input>
<input key={this.props.marker} id="editedLocationName" type="text" placeholder="New Bathroom Location" onChange={this.handleTextBoxState}></input>
<button onClick={() => this.handleSubmitChangesButtonState()}>Submit Changes</button>
</div>
);
}
else {
infoWindowEditBoxes = null
}
and here is my state change function:
handleTextBoxState = (evt) => {
const stateToChange = {}
stateToChange[evt.target.id] = evt.target.value
this.setState(stateToChange)
console.log(stateToChange)
}
Thanks in advance!
I believe component state is getting updated properly in your example, apparently this behavior is related with InfoWindowEx component itself. The way how it is implemented, setState() causes to a re-render InfoWindow component which leads to losing input focus.
You could consider the following updated version of component which prevents re-rendering of info window if it has been already opened:
export default class InfoWindowEx extends Component {
constructor(props) {
super(props);
this.state = {
isOpen: false
};
this.infoWindowRef = React.createRef();
this.containerElement = document.createElement(`div`);
}
componentDidUpdate(prevProps) {
if (this.props.children !== prevProps.children) {
ReactDOM.render(
React.Children.only(this.props.children),
this.containerElement
);
this.infoWindowRef.current.infowindow.setContent(this.containerElement);
this.setState({
isOpen: true
});
}
}
shouldComponentUpdate(nextProps, nextState) {
if (this.state.isOpen) {
return this.props.marker.position.toString() !== nextProps.marker.position.toString();
}
return true;
}
infoWindowClose(){
this.setState({
isOpen: false
});
}
render() {
return <InfoWindow onClose={this.infoWindowClose.bind(this)} ref={this.infoWindowRef} {...this.props} />;
}
}
Demo

Using client side search in react

Search function is working perfectly fine in the console log but when I try to assign that value to rows which is a state. So I setState the rows inside the setState in searchHandler. I know I'm making a mistake but I don't know how to rectify it. OMIT THE UNDECLARED STATES, MINIFIED THE CODE TO WHAT'S NEEDED
function searchingFor(searchingTerm) {
return function(x){
// console.log("searching",x);
return x.name.toLowerCase().includes(searchingTerm.toLowerCase())|| false;
}
}
class Main extends React.Component{
componentWillMount(){
this.props.fetchTopicsTableContent(this.state.sortBy,'ASC',0,this.props.match.params.CategoryName).then(result=> (this.setState({rows:result.payload.data})))
this.props.countTableContent(this.props.match.params.CategoryName).then(result=>(this.setState({count:result.payload})));
}
constructor(props){
super(props);
this.state={
rows:"",
searchTerm:"",
items:""
}
}
onSubmit(values){
values.preventDefault();
}
onSearchHandler(e){
this.setState({searchTerm:e.target.value},()=>{
{this.state.rows.filter(searchingFor(this.state.searchTerm)).map(item=>{
console.log(item);
//this.setState({rows:item})
})}
})
}
render(){
return(
<div>
<h3>Topics</h3>
<hr/>
<div>
<form onSubmit={this.onSubmit.bind(this)}>
<input type="text"
className="searchBar"
value={this.state.searchTerm}
onChange={this.onSearchHandler.bind(this)}
/>
</form>
</div>
</div>
)
}
Okay so lets start with binding your functions in the constructor, not in the markup, clean things up :P
Next, i'm not sure you understand how setting state works as your function goes against it's basic use. You are correctly setting the first state and using the callback (Because it takes time for state to actually be set) which is great. The callback function it's where it goes downhill.
Your mapping function is loading up several setState calls instantly, for each one console.log() will run successfully, but only one of the setStates will actually take effect. On top of that, even if it did work, your rows state will only have a single item. Lets try this:
onSearchHandler(e){
this.setState(prevState => {
return {
rows: prevState.rows.filter(searchingFor(e.target.value)),
searchTerm: e.target.value,
}
});
}
That will get you what I assume is the desired result... you should only ever do one setState at a time, unless you are waiting for the callback on each one, because you can't be sure each one will complete before the next.
Your logic is fine, but the code looks clumsy.I refactored the code so that only necessary logic is present and instead of bind use arrow functions.
Here, try this code on codeSandbox
import React from "react";
import ReactDOM from "react-dom";
class App extends React.Component {
constructor(props){
super(props);
this.state = {
rows: ["asd", "bsd", "csd", "dsd", "esd"],
items: []
}
}
onSearchHandler = (e) => {
this.setState({ items: this.state.rows.filter(str => str.toLowerCase().includes(e.target.value.toLowerCase()))})
}
render(){
return (
<div>
<h3>Topics</h3>
<input type="text"
className="searchBar"
onChange={(e) => this.onSearchHandler(e)}/>
<p>{this.state.items.join('\n')}</p>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));

How to recursively pass up all data from form?

I've got a form, it looks like this:
export default class BookingForm extends React.Component {
constructor(props) {
super(props);
this.state = {data: props.data};
}
render() {
const {booking, vehicleSelect, vehicleData, customer, drivers, fees, occasions} = this.props;
return (
<form className="grid-form">
<div className="row">
<div className="col">
<label>Is this a new or returning customer?</label>
<RadioMenu name="repeat_customer">
<RadioButton value="NEW">New Customer</RadioButton>
<RadioButton value="EXIST">Returning Customer</RadioButton>
</RadioMenu>
</div>
</div>
<div className="row new-customer-row">
<div className="col-1-2">
<label htmlFor="customer.first_name">First Name</label>
<Input id="customer.first_name" name="customer.first_name" type="text"/>
</div>
<div className="col-1-2">
<label htmlFor="customer.last_name">Last Name</label>
<Input id="customer.last_name" name="customer.last_name" type="text"/>
</div>
</div>
// .. more inputs ..
Where <RadioMenu> renders a list of <RadioButton>s which in turn contain an <Input>.
<Input> just looks like this:
export default function Input(attrs) {
return <input {...attrs}/>;
}
I made it a React component hoping I can do something useful with it.
Basically, I want all the form data to be stuffed into this.data.INPUT_NAME as soon as the input is changed. If the input name contains a . then I want to put it into a sub-object. For example, customer.last_name will be stored in this.state.data.customer.last_name. I also want to to use this.state.data to set the initial value for all the Input elements without having to explicitly add a value attribute to each of them; it should just know what value to pull out of the data object by using the input's name.
I don't know how to approach this. My first thought is that instead of returning the <form> I should put it into a variable, and then pre-process it, adding onChange and value attributes to anything of type Input, but even I try that, I don't think it would work on my RadioMenu because RadioMenu is not of type Input and I don't think I could recurse down into its children.
I could try using this context feature but the warnings are scaring me away.
I haven't looked into Flux/Reflux/Redux/xyz yet, but I don't think I really want to incorporate another framework this early in the game; I want to understand how to approach this properly before tucking it away.
So, how can I get all my form data into this.state.data?
The radio widgets look like this. I'm open to changing them if necessary. This is my first custom input widget.
// RadioMenu.jsx
import React from 'react';
import {cloneWithProps} from '../helpers/react-helpers';
import Input from './Input';
export default class RadioMenu extends Input {
constructor(props) {
super(props);
this.state = {value: props.value};
}
onChange = ev => {
this.setState({value: ev.target.value});
if(this.props.onChange) {
this.props.onChange(ev);
}
};
render() {
let {children, name, onChange, ...attrs} = this.props;
return (
<div className="radio-horizontal radio-menu" {...attrs}>
{cloneWithProps(children, btn => ({
name,
checked: btn.props.value == this.state.value,
onChange: this.onChange
}))}
</div>
);
}
}
// RadioButton.jsx
export default function RadioButton({children, ...attrs}) {
return (
<label className="checkable">
<input type="radio" {...attrs}/>
<span>{children}</span>
</label>
);
}
I was trying to use inheritance has so I could pluck out all the Inputs, regardless if they're custom or not, but I can't seem to get this to work in React. mycomp.type instanceof Input doesn't return true for sub-classes. I know React suggests composition over inheritance, but I don't know how to make that work.
This kind of problem is the reason we have libraries/patterns like Redux/Flux, but that doesn't mean it's not possible to solve without React, just a little bit harder.
In this specific case, you have a few options.
Child-Parent Events
If you change your <RadioButton /> component to accept an onChange handler, then you can listen for changes to the button and put them straight into your state.
function RadioButton(props) {
return (
// pass the onChange prop down
<input type="radio" onChange={props.onChange} />
);
}
Then update your <BookingForm /> component to make use of this new handler prop.
const setRadioState = e => this.setState({ radio: e.target.value });
// ...
<RadioMenu name="repeat_customer">
<RadioButton value="NEW" onChange={setRadioState}>New Customer</RadioButton>
<RadioButton value="EXIST" onChange={setRadioState}>Returning Customer</RadioButton>
</RadioMenu>
Accessing the Form
You can listen to the form for the submit event then iterate through the form's elements to build up an object you can put in your state.
render() {
// ...
<form onSubmit={this.onSubmit}>
// ...
},
onSubmit(e) {
const form = e.target;
const elements = form.elements;
// remove numeric keys
const keys = Object.keys(elements).filter(k => /[^\d]/.test(k);
const data = {};
keys.forEach(k => data[k] = elements[k].value);
this.setState(data);
}
If you aren't listening to the submit event and want to submit with say, a button press, then you'll need to use refs to get a instance of the form.
I'm more or less just making this approach up off the top of my head, so be wary of edge cases.
ReactLink will do what you want, but it's on its way out the door. Fortunately, it's easy to recreate this functionality in just a few lines of code.
Instead of using <input>, you can use this component:
import React from 'react';
export default class LinkedStateInput extends React.Component {
render() {
const {value, ...attrs} = this.props;
return <input {...attrs} value={value.value} onChange={ev => value.requestChange(ev.target.value)} />;
}
}
Usage example:
<LinkedStateInput value={this.linkState('passenger_count')} type="text"/>
Now just add a method to your BookingForm to handle the state updates:
linkState(name) {
return {
value: _.get(this.state.data, name, ''),
requestChange: value => {
let data = _.clone(this.state.data);
_.set(data, name, value);
this.setState({data})
}
}
}
I've used lodash here to handle deep sets/gets.
RadioMenu becomes even simpler because now it doesn't even have to remember its own state:
export default function RadioMenu({children, name, valueLink}) {
return (
<div className="radio-horizontal radio-menu">
{
valueLink
? cloneWithProps(children, btn => ({
name,
checked: btn.props.value === valueLink.value,
onChange: ev => valueLink.requestChange(ev.target.value)
}))
: cloneWithProps(children, {name})
}
</div>
);
}

Resources