Using react-bootstrap, I want a checkbox on my form to be checked when my 'inactive' value is true; and not when it's false. So I set the checked attribute to this pretty straightforward line:
checked={inactive}
But I get this error when I click the checkbox: "Warning: Received the string false for the boolean attribute checked. The browser will interpret it as a truthy value. Did you mean checked={false}?"
Here's the relevant code:
render() {
const {
inactive,
...
} = this.state;
return (
<Form.Group as={Row}>
<Form.Label>Inactive<Form.Label>
<Col>
<Form.Check
type="checkbox"
checked={this.state.inactive}
onChange={() => {
if (inactive === 'false') {
this.setState({ inactive: 'true' });
} else {
this.setState({ inactive: 'false' });
}
}}
/>
</Col>
</Form.Group>
);
}
}
So then I changed the checked attribute to the following. But in this case, the the value does not get set correctly when false:
...
checked={inactive === 'true'}
...
if your state is this:
state={
inactive:false,
....
}
Remove this object de-structuring:
const {
inactive,
...
} = this.state;
and make changes as this
<Form.Check
type="checkbox"
checked={this.state.inactive}
onChange={() => {
this.setState({ inactive: !this.state.inactive });
}}
/>
I hope this helps!
See this sandbox
you state needs to be :
this.state = {
inactive: false
}
and remove this object destructuring:
const {
inactive,
...
} = this.state;
Another optimization to avoid if-else...
onChange={()=>this.setState({
inactive: !this.state.invactive
)}
Related
So my problem is simple I guess, I want that when I click an element, my input got the focus in, so this is my methods and constructor on my component :
constructor(props) {
super(props);
this.textInput = React.createRef();
this.state = {
searchValue: ""
};
}
activateSearchZone = action => {
this.props.activateSearchZone(action);
console.log(this.textInput);
this.textInput.current.focus();
};
handleSearchZone = event => {
let searchValue = event.target.value;
this.props.searchForUsers(searchValue, { isSearching: true });
setTimeout(() => {
this.props.searchForUsers(searchValue, {
isSearching: false,
searchDone: true
});
}, 1000);
this.setState({
searchValue
});
};
And this is my component :
{this.props.searchList.activated && (
<div className="search-bar__zone">
<FontAwesomeIcon icon={faSearch} size="xs"></FontAwesomeIcon>
<input
placeholder="Search"
onChange={event => this.handleSearchZone(event)}
value={this.state.searchValue}
type="text"
ref={this.textInput}
></input>
<FontAwesomeIcon
icon={faTimesCircle}
onClick={() => this.activateSearchZone(false)}
></FontAwesomeIcon>
</div>
)}
The console log shows that the current value is null, I understand now why, it is because my element is just rendered I think, but I want the focus in my input when clicking.
How can I do that ?
An help would be much appreciated.
You can focus an input element with autofocus attribute. In react, it will be like <input type="text" autoFocus />, this will do the job.
For detailed explanation, please refer the link https://davidwalsh.name/react-autofocus
That's because react doesn't knows about the ref on initial render. You need to use forwardRef. It is HOC that wraps your component and tells react that there is some ref. And it will not render that until it is available. Here is an example:
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
I'm trying to enable button if both the checkboxes are checked, I have nonworking stackblitz link
I have added the only crux of functionality. Please look into the link for the nonworking demo
import React, { useState } from 'react';
import { render } from 'react-dom';
function App (){
const [checked, toggleCheckbox] = useState({ checkbox1: false, checkbox2: false, disabled: true });
const getDisabled = (state) => {
if (state.checkbox1 || state.checkbox2) {
return false;
} else if (!state.checkbox1 && !state.checkbox2) {
return true;
} else {
return true;
}
};
const handleCheckbox = (checkbox) => {
toggleCheckbox({
...checked,
[checkbox]: !checked[checkbox],
disabled: getDisabled(checked)
});
console.log(checked);
};
const checkDisable = checked.disabled ? 'disabled' : ''
return (
<div>
<div>
<label>
<input
type="checkbox"
className="filled-in"
onChange={() => handleCheckbox('checkbox1')}
checked={checked.checkbox1}
/>
<span className="black-text">Checkbox1</span>
</label>
</div>
<div>
<label>
<input
type="checkbox"
className="filled-in"
onChange={() => handleCheckbox('checkbox2')}
checked={checked.checkbox2}
/>
<span className="black-text">checkbox2</span>
</label>
</div>
<div>
<a className={checkDisable} href="#!">
Next Step
</a>
</div>
</div>
);
}
render(<App />, document.getElementById('root'));
The functionality should be as follows:
The button should be enabled only if both the checkboxes are checked
On unchecking anyone checkboxes it should disable the button
You can simply check the state of both checkbox values.
const isDisabled = !(checked.checkbox1 && checked.checkbox2)
const checkDisable = isDisabled ? 'disabled' : ''
No need to change elsewhere.
Forked stackblitz link.
https://stackblitz.com/edit/react-jscqwr?file=index.js
Answer to the comment.
Hey, that worked! I could see in the log that the state one step below the updated state for an instance after clicking in the first checkbox { checkbox1: false, checkbox: false, disabled: false } after clicking the second checkbox the log { checkbox1: true, checkbox: false, disabled: false }
The reason you are seeing outdated state is because the state updator toggleCheckbox batches the update, thus you'd need to check for the updated status in an effect, which monitors the updated status.
Dynamic number of checkboxes.
I've updated the stack to track dynamic number of checkboxes.
New fork~
https://stackblitz.com/edit/react-pl1e2n
Looks like this.
function App() {
const length = 6;
1️⃣ Generate the initial checkbox states - this prevents un/controlled component error.
const initialCheckboxes = Array
.from({ length }, (_, i) => i + 1)
.reduce((acc, id) => (acc[id] = false, acc), {})
const [checked, toggleCheckbox] = useState(initialCheckboxes);
const [isDisabled, setIsDisabled] = useState(false)
const handleCheckbox = id => {
toggleCheckbox(previous => ({
...previous,
[id]: !previous[id]
}));
};
2️⃣ Update the disable state when the checkbox is selected.
useEffect(() => {
👇 Enable when all checkboxes are not checked - 😅
setIsDisabled(!Object.values(checked).every(_ => !!_))
}, [checked])
3️⃣ Dynamically generate checkboxes
const checkboxElements = Array.from({ length }, (_, i) => i + 1)
.map(id => (
<div key={id}>
<label>
<input
type="checkbox"
className="filled-in"
onChange={() => handleCheckbox(id)}
checked={checked[id]}
/>
<span className="black-text">Checkbox{id}</span>
</label>
</div>
))
return (
<div>
{checkboxElements}
<div>
<a className={isDisabled ? 'disabled' : ''} href="#!">
Next Step
</a>
</div>
</div>
);
}
I want to know is it possible to access the next or prev element in ReactJs?I have two inputs by labels a and b.In handlerChecked function I want to check the attribute checked of both inputs.For example I checked a and I want also to check b was checked or not. How can I do it?
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
.
.
.
}
}
.
.
.
handlerChecked = (e, elem) => {
let isChecked = e.target.checked
let value = e.target.value
let checknext = e.target.next('input').checked //In this part I want to check the attribute checked of other Input////
}
.
.
.
render() {
return (
<div>
<input type="checkbox" className="" value="0" onChange={this.handlerChecked} /> <label><span>a</span></label>
<input type="checkbox" className="" value="1" onChange={this.handlerChecked} /> <label><span>b</span></label>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('Result'))
The short answer is no, React doesn't work that way, you can't go up and down an element's ancestor's tree to find sibling elements.
A common way to implement this feature is to give each checkbox a name attribute.
For example:
<div>
<input name="check1" type="checkbox" onChange={this.handlerChecked} checked={this.state.check1} /> <label><span>a</span></label>
<input name="check2" type="checkbox" onChange={this.handlerChecked} checked={this.state.check2} /> <label><span>b</span></label>
</div>
handle these two checkboxes with one handler
const handlerChecked = (e) => {
const {name, checked} = e.target
this.setState({
[name]: checked
})
}
then in your state keep track of those 2 names like this:
this.state = {
check1: false,
check2: false
}
Given a react form with multiple radio buttons and a text input that is visible only when the other option radio button is selected, I currently have the submit button disabled until a radio button is selected. However, if the other option is selected, the submit button will still work even if there is no text in the input field associated with it. How can I check the length of the input box if and only if the other option is selected?
class CancelSurvey extends React.Component {
constructor (props) {
super(props)
this.state = {
reasons: [],
reason: {},
otherReasonText: undefined,
submitting: false
}
this.processData = this.processData.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
this.setReason = this.setReason.bind(this)
this.setOtherReasonText = this.setOtherReasonText.bind(this)
this.otherReason = {
reason_id: 70,
client_reason: 'other'
}
}
componentDidMount () {
this.fetchSurvey()
}
/**
* Fetch reasons
*/
fetchSurvey (cb) {
superagent
.get('/api/user/survey')
.then(this.processData)
}
processData (data) {
this.setState({ reasons: data.body })
}
async handleSubmit (e) {
e.preventDefault()
await this.setState({ submitting: true })
const { reason, otherReasonText } = this.state
superagent
.post('/api/user/survey')
.send({
optionId: reason.reason_id,
optionText: reason.client_reason,
otherReasonText
})
.then(async (data) => {
await this.setState({ submitting: false })
if (data.body.success) {
this.props.setStep(OFFER)
}
})
}
setOtherReasonText (e) {
this.setState({ otherReasonText: e.target.value })
}
setReason (reason) {
this.setState({ reason })
}
/**
* render
*/
render (props) {
const content = this.props.config.contentStrings
const reasons = this.state.reasons.map((reason, i) => {
return (
<div
className='form-row'
key={i}>
<input type='radio'
id={reason.reason_id}
value={reason.client_reason}
name='reason'
checked={this.state.reason.reason_id === reason.reason_id}
onChange={() => this.setReason(reason)} />
<label htmlFor={reason.reason_id}>{reason.client_reason}</label>
</div>
)
})
return (
<div className='cancel-survey'>
<form className='cancel-survey-form'>
{ reasons }
<div className='form-row'>
<input
type='radio'
id='other-option'
name='reason'
onChange={() => this.setReason(this.otherReason)} />
<label htmlFor='other-option'>
Other reason
</label>
</div>
{ this.state.reason.reason_id === 70 &&
<div>
<input
className='valid'
type='text'
id='other-option'
name='other-text'
placeholder="placeholder"
onChange={this.setOtherReasonText} />
</div>
}
<div className='button-row'>
<button
disabled={!this.state.reason.client_reason}
className={btnClassList}
onClick={this.handleSubmit}>
<span>Submit</span>
</button>
</div>
</form>
</div>
)
}
}
export default CancelSurvey
disabled={
!this.state.reason.client_reason
||
(this.state.reason.client_reason === 'other' && !this.state.otherReasonText)
}
If you want to make sure otherReasonText is not just empty spaces, use otherReasonText: '' as initial state then check !this.state.otherReasonText.trim().
Do some conditional logic before like:
const reasonId = this.state.reason.reason_id;
const otherReasonText = this.state.otherReasonText;
const clientReason = this.state.reason.client_reason;
const shouldDisableButton = !clientReason || (reasonId === 70 && otherReasonText.length === 0)
...
<div className='button-row'>
<button
disabled={shouldDisableButton}
className={btnClassList}
onClick={this.handleSubmit}>
<span>Submit</span>
</button>
</div>
If this.state.editMode is false then the input doesn't show, in which case the ref setup for this.textInput is undefined until the input shows. However if I want to click on the span to show the input I need to focus on the input.
Does anybody have an elegant solution for this or am I overthinking? Thank you in advance.
focusOnTextInput() {
this.textInput.focus();
}
setEditMode() {
this.editMode = !this.editMode;
this.setState(() => ({
editMode: this.editMode
}));
if (this.editMode) {
this.focusOnTextInput();
}
}
render() {
return (
<li className="task">
{
this.state.editMode ?
<input
type="text"
ref={(input) => { this.textInput = input; }}
onKeyUp={this.keyUpCheck}
onChange={this.changeValue}
value={this.state.newTitle} /> :
<span onClick={this.setEditMode}>{ this.state.title }</span>
}
<span>{ this.props.done }</span>
<span>{ this.props.inProgress }</span>
<button onClick={this.props.onRemove}>X</button>
</li>
)
}
Okay I added the change regarding the editMode which works perfectly and also the focus now works as ref means something... EXCELLENT, thank you Tony :-)
setEditMode() {
this.setState(() => ({
editMode: !this.state.editMode
}));
}
componentDidUpdate(prevProps, prevState) {
if (this.state.editMode) {
this.focusOnTextInput();
}
}
Now how do I set this as complete and give you full marks..?
If you use componentDidUpdate(prevProps, prevState) you will be able to check if this.state.editMode is now set and call your this.focusOnTextInput()