I am having hardtime by fixing this component. I got error when I am selecting multiple item with checkbox. But in my other component, there is no error, same code. Please check my code below, thank you guys.
export default class TreeNode extends React.Component{
constructor(props){
super(props)
this.state = {
collapsed: true,
checked: []
}
}
onClick(){
this.setState({
collapsed : !this.state.collapsed
});
}
checkBoxHandle(id,e){
if (e.target.checked){
let {checked} = this.state
checked.push(id)
this.setState({checked :checked })
} else{
//If checkbox uncheck = remove in the list
let {checked} = this.state
const getIndex = checked.indexOf(id)
checked.splice(getIndex,1)
this.setState({checked : checked})
}
}
render(){
let subtree = null;
if (this.props.data.children){
subtree = this.props.data.children.map(function(child){
return <TreeNode key= {child.id} data ={child} />;
}.bind(this))
}
const temp_id = this.props.data.id
var arrowClassName = 'tree-node-arrow';
var containerClassName = 'tree-node-children'
if (subtree){
return (
<div className="tree-node">
<input type="checkbox" onClick ={this.checkBoxHandle.bind(this,this.props.data.id)}/>
<a data-id={this.props.data.id}>
{this.props.data.description}
</a>
<div className={containerClassName}>
{subtree}
</div>
</div>
);
}
else {
return (
<div className="tree-node-leaf">
<input type="checkbox" onClick ={this.checkBoxHandle.bind(this,this.props.data.id)}/>
<a data-id={this.props.data.id}>
{this.props.data.description}
</a>
</div>
);
}
}
}
I am updating the checked state everytime there is checked item, and I am removing if the user unchecked the checkbox.
It's because you use the mutable methods for checked like push and splice while a component's state is immutable. So do it in an immutable way with rest operator and filter method like this:
class Checkboxes extends React.Component {
state = {
checked: []
};
onChange = (e) => {
const { checked } = this.state;
const { id } = e.target;
if (checked.indexOf(id) === -1) {
this.setState({
checked: [...checked, id]
});
} else {
this.setState({ checked: checked.filter(checkedId => checkedId !== id) });
}
}
render() {
const { checked } = this.state;
console.log(`CHECKED: ${checked}`);
return (
<div className="checkboxes">
<label htmlFor="checkbox1">Checkbox 1</label>
<input type="checkbox" onChange={this.onChange} id="1" checked={checked.indexOf("1") !== -1} />
<br />
<label htmlFor="checkbox2">Checkbox 2</label>
<input type="checkbox" onChange={this.onChange} id="2" checked={checked.indexOf("2") !== -1} />
<br />
<label htmlFor="checkbox3">Checkbox 3</label>
<input type="checkbox" onChange={this.onChange} id="3" checked={checked.indexOf("3") !== -1} />
</div>
);
}
}
Here is the working Codepen example.
Related
React newbie here.
I'm trying to make a multi-step form to get some details from the user and for some of the nested views, there are only radio buttons. The handleChange works fine on text type but how can I handle radio buttons?
React does not render the radio button that is used to render in AngularJS, so I am a bit confused. I can choose multiple radio button and all of them looks like checkboxes instead of choosing only one
MainForms.js
export class UserForm extends Component {
state = {
step: 1,
tema: '',
area: '',
type: '',
name: ''
};
// Proceed to next step
nextStep = () => {
const { step } = this.state;
this.setState({
step: step + 1
});
};
// Go back to prev step
prevStep = () => {
const { step } = this.state;
this.setState({
step: step - 1
});
};
// Handle fields change
handleChange = input => e => {
this.setState({ [input]: e.target.value });
console.log(e.target.value)
};
render() {
const { step } = this.state;
const { area, name, type, tema} = this.state;
const values = { area, name, type, tema};
switch (step) {
case 1:
return (
<FormUserDetails
nextStep={this.nextStep}
handleChange={this.handleChange}
values={values}
/>
);
FormUserDetails.js
export class FormUserDetails extends Component {
continue = (e) => {
e.preventDefault();
this.props.nextStep();
};
back = (e) => {
e.preventDefault();
this.props.prevStep();
}
render() {
const { handleChange } = this.props;
return (
<div className="box item2">
<div className="radio">
<label>
<input
type="radio"
onChange={handleChange}
/>
Basic
</label>
</div>
);
}
}
form example
For the radio input not to "work like an checkbox" they all need the same name in this case its "yyy".
<div className="box item2">
<div className="radio">
<label>
<input
type="radio"
name="yyy"
value="123"
onChange={handleChange}
/>
Basic
</label>
</div>
<div className="radio">
<label>
<input
type="radio"
name="yyy"
value="456"
onChange={handleChange}
/>
Basic
</label>
</div>
</div>
Your handleChange receives the event and not some input prop. To see if the radio input is checked or not you can use the checked property.
handleChange = (e) => {
const target = e.target;
// do whatever you want with the state :)
this.setState({ [target.name]: target.value });
};
I'm not 100% sure if I understand your question correct and if my answer helps you, but what I have made in my solution is something like this:
export const RadioButtonInputField = ({label, onChangeOut}) => {
const [state, setState] = useState(true);
const setOnChange = (value) => {
onChangeOut({value: value});
setState(value);
};
return (
<div className={`dynamic-input-container`}>
<div className={'radio-button-wrapper'}>
<p className={'radio-title'}>{label}</p>
<label className={'radio-label first-radio-label'}>
<input
type='radio'
value={true}
checked={state === true}
className={'radio-input'}
onChange={() => {
setOnChange(true);
}}
/>
<span className={'radio-btn-label'}>Yes</span>
</label>
<br />
<label className={'radio-label'}>
<input
type='radio'
value={false}
checked={state === false}
className={'radio-input'}
onChange={() => {
setOnChange(false);
}}
/>
<span className={'radio-btn-label'}>No</span>
</label>
</div>
</div>
);
}
I'm practicing react and I'm trying to add an item to a list from input by clicking submit button.
I prefer to use state and setState
I'd LOVE some help.
I don't think my code is needed but here is it anyway:
class App extends Component {
state = {
userInput: ""
}
inputChangeHandler = (e) => {
this.setState({userInput: e.target.value})
}
listAddHandler = () => {
var listElement = document.createElement('li')
listElement.appendChild("ul")
}
render() {
return (
<div className="checklist">
<h1>This is an inventory</h1>
<input type="text" value={this.state.userInput} onChange={this.inputChangeHandler} placeholder="Insert item"/>
<button onClick={this.listAddHandler}>Submit</button>
<ul>
<li>
</li>
</ul>
</div>
)
}
}
You need to keep track of listed items within your state as an array:
const { Component } = React,
{ render } = ReactDOM,
rootNode = document.getElementById('root')
class App extends Component {
state = {
listItems: [],
userInput: '',
}
inputChangeHandler = ({target:{value}}) => this.setState({
userInput: value
})
submitHandler = e =>{
e.preventDefault()
this.setState({
listItems: [...this.state.listItems, this.state.userInput],
userInput: ''
})
}
render() {
return (
<div>
<ul>
{
this.state.listItems.map((li,key) => <li {...{key}}>{li}</li>)
}
</ul>
<form onSubmit={this.submitHandler}>
<input value={this.state.userInput} onChange={this.inputChangeHandler} />
<input type="submit" value="Submit" />
</form>
</div>
)
}
}
render (
<App />,
rootNode
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>
Hi I write a small component
export default class TextInput extends React.Component {
constructor(props) {
super(props);
this.onKeyPress = this.onKeyPress.bind(this);
this.state = { tags: [], value: "" };
}
onKeyPress(e) {
if (e.key === "Enter") {
this.setState({ tags: [...this.state.tags, e.target.value], value: "" });
}
}
render() {
return (
<div>
<div styleName="fieldset width-95">
<label>Tags</label>
<div>
<div>
{this.state.tags.map(tag => (
<span>{tag}</span>
))}
</div>
<input
type="text"
onKeyPress={this.onKeyPress}
value={this.state.value}
/>
</div>
</div>
</div>
);
}
}
after writing 1st time when I enter.it creates a tag but after that, I can't type anything in the input field. can anyone please explain how to enable typing so that I will be able to create another tag.
You also need an onChange handler as well to update state on user-input. Otherwise this.state.value will never update.
class TextInput extends React.Component {
constructor(props) {
super(props);
this.onKeyPress = this.onKeyPress.bind(this);
this.state = { tags: [], value: "" };
}
onKeyPress(e) {
if (e.key === "Enter") {
this.setState({ tags: [...this.state.tags, e.target.value], value: "" });
}
}
handleOnChange = e => {
this.setState({
value: e.target.value
});
};
render() {
return (
<div>
<div styleName="fieldset width-95">
<label>Tags</label>
<div>
<div>
{this.state.tags.map(tag => (
<span>{tag}</span>
))}
</div>
<input
type="text"
onChange={this.handleOnChange}
onKeyPress={this.onKeyPress}
value={this.state.value}
/>
</div>
</div>
</div>
);
}
}
See working sandbox: https://codesandbox.io/s/serene-https-t02h2
The problem is that you forgot to add an onClick event for the input, this will handle when you type something in it (You only need to update the state every time the onChange event is fire), like this (I've also made an update to a more ES6 syntax):
import React, { Component } from 'react';
export default class TextInput extends Component {
state = { tags: [], value: "" };
onKeyPress = e => {
if (e.key === "Enter") {
this.setState({ tags: [...this.state.tags, e.target.value], value: "" });
}
};
onClick = e => {
if (e && e.target && e.target.value) {
this.setState({ value: e.target.value });
}
};
render() {
const { tags, value } = this.state;
return (
<div>
<div styleName="fieldset width-95">
<label>Tags</label>
<div>
<div>
{tags.map(tag => (
<span>{tag}</span>
))}
</div>
<input
type="text"
onChange={this.onClick}
onKeyPress={this.onKeyPress}
value={value}
/>
</div>
</div>
</div>
);
}
}
You can try below code.And you remove value which you are set on state.And use onChange method.
import React, { Component } from 'react';
export default class TextInput extends React.Component {
constructor(props) {
super(props);
this.onKeyPress = this.onKeyPress.bind(this);
this.state = { tags: [] };
}
onKeyPress(e) {
if (e.key === "Enter") {
this.setState({ tags: [...this.state.tags, e.target.value], value:
e.target.value });
console.log("tag:",this.state.tags)
}
}
handleInputChange = (event) => {
this.setState({ [event.target.name]: event.target.value });
};
render() {
return (
<div>
<div styleName="fieldset width-95">
<label>Tags</label>
<div>
<div>
{this.state.tags.map(tag => (
<span >{tag}</span>
))}
</div>
<input
type="text"
onKeyPress={this.onKeyPress}
name="demo"
value={this.state.value}
onChange={this.handleInputChange}
/>
</div>
</div>
</div>
);
}
}
I am trying to run a function on a Todo list that when a todo is added. A function will check the input box to check if its empty and if its empty, not do anything.
However, after using the function to check if the input is empty, it always returns False even when its empty. Where is the bug here?
The function name in question is "checkInput()" and it runs from the main submit button on the page
import React from "react";
import "./App.css";
import { isTemplateElement } from "#babel/types";
class TodoListt extends React.Component {
state = {};
constructor(props) {
super(props);
this.state = {
userInput: "",
list: [],
};
}
changeUserInput(input) {
this.setState({
userInput: input
})
}
addToList() {
const { list, userInput } = this.state;
this.setState({
list: [...list, {
text: userInput, key: Date.now(), done: false
}],
userInput: ''
})
}
handleChecked(e, index) {
console.log(e.target.checked);
const list = [...this.state.list];
list[index] = { ...list[index] };
list[index].done = e.target.checked;
this.setState({
list
})
}
checkInput() {
console.log(this.state.userInput);
userInput: '' ? console.log("True") : console.log("False")
}
render() {
return (
<div className="to-do-list-main">
<input
onChange={(e) => this.changeUserInput(e.target.value)}
value={this.state.userInput}
type="text"
/>
<button onClick={() => { this.checkInput(); { this.addToList(this.state.userInput) } }}>Add todo</button>
{this.state.list.map((list, index) => (
<div className="form">
<ul>
<li><input type="checkbox" onChange={(e) => this.handleChecked(e, index)} />
<span style={{ textDecoration: list.done ? 'line-through' : 'inherit' }}>
{list.text}
</span>
</li>
</ul>
</div>
))}
</div>
);
}
}
export default TodoListt;
I have one component (Fuel) which I use in two other components (Search and SmallFilters) :
Search component is as follows :
class search extends React.Component {
render() {
const language = this.props.language.default.portal;
return (
<div>
<div className="searchTitle"><FontAwesome name="search" className="portalFaIcon"/> {language.search}</div>
<Fuel language={language} actionFilters={this.props.actionFilters} filters={this.props.filters}/>
</div>
);
}
}
function mapStateToProps(state, ownProps){
return {
favorites: state.favorites,
filters: state.filters,
carsToShow: state.carsToShow
};
}
function mapDispatchToProps(dispatch){
return {
actionFilters: bindActionCreators(filterActions, dispatch),
actionCarsToShow: bindActionCreators(actionCarsToShow, dispatch)
};
}
export default connect(mapStateToProps, mapDispatchToProps)(search);
The SmallFilters is as follows :
render(){
return (
<div className="filters noPadding col-xl-8 col-lg-6 col-md-6 col-sm-5 col-xs-12">
<ReactCSSTransitionGroup transitionName="example" transitionAppear={true} transitionAppearTimeout={500} transitionEnterTimeout={500} transitionLeaveTimeout={500}>
<Fuel recap={true} title={_.startCase(_.toLower(filter_names.fuel))} {...this.props}/>
</ReactCSSTransitionGroup>
</div>
);
}
The Fuel component is as follows :
import React from 'react';
import FontAwesome from 'react-fontawesome';
import {Link} from 'react-router';
import { filter_names } from './filterActions';
export default class fuel extends React.Component {
constructor(props){
super(props);
this.state = this.getFilterValues()
}
emptyValues(){
return {
checkboxDiesel: false,
checkboxBenzine: false
}
}
handleFilter(){
if(this.state.checkboxDiesel || this.state.checkboxBenzine){
this.props.actionFilters.addFuelFilter(this.state);
}else{
this.props.actionFilters.removeFuelFilter();
}
}
handleDiesel(event){
const checkbox = event.target.checked;
this.setState({checkboxDiesel: checkbox, checkboxBenzine: this.state.checkboxBenzine}, () => this.handleFilter());
}
handleBenzine(event){
const checkbox = event.target.checked;
this.setState({checkboxBenzine: checkbox, checkboxDiesel: this.state.checkboxDiesel}, () => this.handleFilter());
}
deActivate(event) {
event.preventDefault();
this.setState(this.emptyValues(), () => this.handleFilter());
}
getFilterValues(){
debugger;
if(!this.props.filters.some(i => i.name === filter_names.fuel)){
return this.emptyValues();
}
return {
checkboxDiesel: this.props.filters.filter(f => f.name === filter_names.fuel).map(i => i.values.map(v => v.checkboxDiesel)),
checkboxBenzine: this.props.filters.filter(f => f.name === filter_names.fuel).map(i => i.values.map(v => v.checkboxBenzine))
};
/*let values = {};
this.props.filters.filter(f => {
if(f.name == filter_names.fuel){
values.checkboxDiesel = f.values[0].checkboxDiesel;
values.checkboxBenzine = f.values[0].checkboxBenzine;
}
});
return values;*/
}
renderSmall() {
let diesel = this.getFilterValues().checkboxDiesel ? "Diesel" : "";
let benzine = this.getFilterValues().checkboxBenzine ? "Benzine" : "";
return (
<div className="filter">
{this.props.title} <Link to="" onClick={this.deActivate.bind(this)}><FontAwesome name="times" className="portalFaRedIcon"/></Link>
<div className="filterValues">{diesel} {benzine}</div>
</div>
);
}
render() {
const language = this.props.language;
if(this.props.recap) return this.renderSmall();
console.log(this.props.filters);
return (
<div>
<div className="priceTitle" style={{padding: '5px 0'}}>{language.fuel}</div>
<div className="transmissionValues">
<input type="checkbox" onChange={this.handleDiesel.bind(this)} checked={this.getFilterValues().checkboxDiesel}/> <span>Diesel</span>
</div>
<div className="transmissionValues">
<input type="checkbox" onChange={this.handleBenzine.bind(this)} checked={this.getFilterValues().checkboxBenzine}/> <span>Benzine</span>
</div>
</div>
);
}
}
The problem is, when I click on one of those checkboxes, both are checked. And If I click on the same checkbox both are unchecked. But if I click on the other one nothing happends.
This.props.filters comes from redux store and it's something like this if one of those checkboxes is checked :
[{name: "FUEL", values: [{checkboxDiesel: true, checkboxBenzine: false}]}]
Any advice?
By a long shot, I think you should just use this.state to update your input's value. Read controlled components from the docs.
render() {
const language = this.props.language;
if(this.props.recap) return this.renderSmall();
console.log(this.props.filters);
return (
<div>
<div className="priceTitle" style={{padding: '5px 0'}}>{language.fuel}</div>
<div className="transmissionValues">
<input type="checkbox" onChange={this.handleDiesel.bind(this)} checked={this.state.checkboxDiesel}/> <span>Diesel</span>
</div>
<div className="transmissionValues">
<input type="checkbox" onChange={this.handleBenzine.bind(this)} checked={this.state.checkboxBenzine}/> <span>Benzine</span>
</div>
</div>
);
}
If there are any side-effects of this action, you can do that in handleDiesel or handleBenzine methods. Let me know if it works. Meanwhile, I'll try to understand more from your code.