I am trying to control my radio buttons with state so that i can add an active class for a radio button when it is clicked. Im stuck now because i need to double click to make the radio button change and after they changed once, i cant get anymore console output. Can someone see what is wrong?
import React, { Component } from 'react'
class CustomRadio extends Component {
constructor(props) {
super(props);
this.state = {
name:'',
id:'',
value:'',
onChange:'',
label:'',
validationMsg:'',
rbValue:'',
checked:''
};
}
onSelect = (e) => {
this.setState({
rbValue: e.target.value
});
//console.log(this.state.rbValue);
console.log(e.target.value);
console.log(this.props.checked);
}
// setClass = () => {
// if (this.state.rbChecked === true)
// return "active"
// else
// return "inactive"
// }
render() {
//let rbActiveClass = this.setClass();
return (
// <div className={`form-item custom-radio ${rbActiveClass}`}>
<div className={`form-item custom-radio`}>
{this.props.label &&
<label htmlFor={this.props.id}>
{this.props.label}
</label>
}
<input
type="radio"
id={this.props.id}
name={this.props.name}
value={this.props.value}
checked={this.state.rbValue === this.props.checked}
//defaultChecked={this.props.defaultChecked}
onChange={this.onSelect.bind(this)}
/>
{this.props.validationMsg &&
<span className="validation-message">
{this.props.validationMsg}
</span>
}
</div>
)
}
}
export default CustomRadio
just change component constructor:
class CustomRadio extends Component {
constructor(props) {
super(props);
this.state = {
//...
rbValue:props.checked,
//...
};
}
and also input component:
<input
//...
checked={this.state.rbValue}
//...
/>
Related
Hello I am trying to render my PostOnWall component I made using an onClick function. The goal that every time someone clicks the button handleClick will render one new component on the screen each time. So if I click the button three times i should see three PostOnWall components rendered on my screen. Please tell me what I am doing wrong.
class Textbox extends Component {
constructor(props) {
super(props);
this.handleClick.bind(this);
this.state = {
textArea: "",
text: "",
show: false,
curTime : new Date().toLocaleString(),
};
}
handleChange(event) {
const myValue = event.target.value;
this.setState({
textArea: myValue
})
console.log(this.state)
}
handleClick= () => {
this.setState({text:this.state.textArea,
show: !this.state.show});
return (
<div>
{this.state.show && <PostOnWall PostOnWall={this.props.PostOnWall} text={this.state.text} time={this.state.curTime}/>}
</div>
);
}
showNewPost
render() {
return (
<div>
<textarea className="Textbox"
rows="2" cols="30"
type = "text"
onChange={this.handleChange.bind(this)}
value={this.state.textArea} >
</textarea>
<button className="postbutton" onClick={this.handleClick.bind(this)}>Post</button>
</div>
);
}
}
export default Textbox;
That should do the trick for you;
import React, { Component } from 'react';
class Textbox extends Component {
constructor(props) {
super(props);
this.handleClick.bind(this);
this.state = {
textArea: '',
text: '',
show: false,
curTime: new Date().toLocaleString(),
};
}
handleChange = (event) => {
const myValue = event.target.value;
this.setState({
textArea: myValue
});
}
handleClick= () => {
this.setState({
text: this.state.textArea,
show: !this.state.show
});
}
render() {
return (
<div>
<textarea
className="Textbox"
rows="2"
cols="30"
type="text"
onChange={this.handleChange.bind(this)}
value={this.state.textArea}
/>
<button
className="postbutton"
onClick={this.handleClick}
type="button"
>
Post
</button>
{
this.state.show &&
<PostOnWall
PostOnWall={this.props.PostOnWall}
text={this.state.text}
time={this.state.curTime}
/>
}
</div>
);
}
}
You should use the function called on click to change the state only. Then render (or not) the PostOnWall component based on the state value.
you need to add state which increase on click and then render the component depending on how many time the button is clicked. here the codeSandbox for what you are trying to achieve.
I am trying to update my state by using a click function. However for some reason it is not updating. Could someone please explain to me what I am doing wrong?class Textbox extends
Component {
constructor(props) {
super(props);
this.handle = this.handle.bind(this);
this.state = {
text: 'jkjkljkljl'
}
}
handle(event) {
const myValue = event.target.value;
this.setState({
text: myValue
})
console.log(this.state)
}
render() {
return (
<div>
<textarea className="Textbox" rows="2" cols="30" type = "text" >
</textarea>
<button className="postbutton" onClick={this.handle.bind(this)}>Post</button>
<h1>{this.state.text}</h1>
</div>
);
}
}
export default Textbox;
Here is an updated version of your code that works.
Issue was that you were trying to set the value of the button to the state.
What you should do is setup textarea as a controlled input (have value and onChange setup as I did below) and use that value on click.
class Component extends React.Component {
constructor(props) {
super(props);
this.state = {
textArea: "",
text: "jkjkljkljl"
};
}
handle(event) {
console.log(event);
this.setState({
text: this.state.textArea
});
console.log(this.state);
}
handleChange(event) {
this.setState({ textArea: event.target.value });
}
render() {
return (
<div>
<textarea
className="Textbox"
rows="2"
cols="30"
value={this.state.textArea}
onChange={this.handleChange.bind(this)}
/>
<button className="postbutton" onClick={this.handle.bind(this)}>
Post
</button>
<h1>{this.state.text}</h1>
</div>
);
}
}
It seems you are trying to handle a form using React/JSX. There are great libraries for this purpose (React Forms).
This is the proper code:
class App extends React.Component {
constructor(props) {
super(props);
this.handle = this.handle.bind(this);
this.state = {
text: 'Static'
}
}
handleOnChange(event) {
this.setState({text: event.target.value});
}
handleSubmit(event) {
if (event.keyCode == 13) return this.sendData();
}
render() {
return (
<div>
<form onKeyUp={this.handleOnChange}>
<textarea className="Textbox"
rows="2" cols="30" type="text"
>
</textarea>
<button className="postbutton"
onClick={this.handleSubmit.bind(this)}>
Post
</button>
</form>
<h1>{this.state.text}</h1>
</div>
);
}
}
React.render(<App />, document.getElementById('app'));
In your example, you are binding the state to the root of the button and not the textarea. If you want a static example (whereas the above code changes as you type), you may simply handle the enter key via if (event.keyCode == 13) return this.sendData() and remove the onChange.
I have multiple buttons on my screen and and inside same container I have another label, on click I want to show the label and then hide after few seconds.
I am controlling through this.state problem is when event fires it shows all labels and then hides all. I found few solutions like assign ids etc and array for buttons.
But issue is there can be unlimited buttons so thats not the way to go to set state for each button. Or if there is any other possible way.
export default class App extends React.Component {
constructor(props) {
super();
this.state = {
visible: false
}
}
_handleClick = () => {
this.setState({
visible: !this.state.visible
});
setTimeout(() => {
this.setState({
visible: false
});
},2000);
}
render() {
return (
<div>
<button onClick={this._handleClick}>Button 1</Text></button>
{this.state.visible && <span style={styles.pic}>
Pic
</span>
}
</div>
<div>
<button onClick={this._handleClick}>Button 2</Text></button>
{this.state.visible && <span style={styles.pic}>
Pic
</span>
}
</div>
<div>
<button onClick={this._handleClick}>Button 3</Text></button>
{this.state.visible && <span style={styles.pic}>
Pic
</span>
}
</div>
</div>
);
}
}
You need each button to have its own state... So make each button a Component!
class App extends React.Component {
render() {
return <div>
<Button>1</Button>
<Button>2</Button>
<Button>3</Button>
<Button>4</Button>
</div>
}
}
class Button extends React.Component {
constructor(props) {
super();
this.state = {
visible: false
}
}
_handleClick = () => {
this.setState({
visible: !this.state.visible
});
setTimeout(() => {
this.setState({
visible: false
});
}, 2000);
}
}
If there are unlimited buttons, then you can set the state like this regarding which button is clicked.
_handleClick = (id) => {
this.setState({ [id]: true })
}
id will be the unique id of each button.
Here is a simple example to show how to set the state.
https://codesandbox.io/s/k38qyv28r
I have a parent container which has a couple of child components. When the user clicks onClick={props.toggleReviewForm}, the function
toggleReviewForm () {
this.setState(prevState => ({
reviewFormActive: !prevState.reviewFormActive,
displayNameModalActive: !prevState.displayNameModalActive
}))
}
toggles the reviewForm state to visible. It's visibility is set with reviewFormActive={reviewFormActive} in the child component and the parent has `this.state = {reviewFormActive: false} set in the constructor. I am passing
displayNameModalActive={displayNameModalActive}
into the child component for the modal, but getting the error
Uncaught TypeError: Cannot read property 'displayNameModalActive' of undefined at DisplayNameModal.render
Parent Container
class ReviewsContainer extends React.Component {
constructor (props) {
super(props)
this.state = {
reviewFormActive: false,
displayNameModalActive: false
}
this.config = this.props.config
this.toggleReviewForm = this.toggleReviewForm.bind(this)
}
toggleReviewForm () {
this.setState(prevState => ({
reviewFormActive: !prevState.reviewFormActive,
displayNameModalActive: !prevState.displayNameModalActive
}))
}
render () {
const {
reviewFormActive,
displayNameModalActive
} = this.state
return (
<div className='reviews-container'>
<ReviewForm
config={this.config}
reviewFormActive={reviewFormActive}
toggleReviewForm={this.toggleReviewForm}
/>
{this.state.displayName &&
<div className='modal-container'>
<DisplayNameModal
bgImgUrl={this.props.imageUrl('displaynamebg.png', 'w_1800')}
config={this.config}
displayNameModalActive={displayNameModalActive}
displayName={this.state.displayName}
email={this.state.email} />
</div>
}
</div>
)
}
}
export default ReviewsContainer
Child Component (modal)
class DisplayNameModal extends React.Component {
constructor (props){
super(props)
this.state = {
displayName: this.props.displayName,
email: this.props.email.split('#')[0]
}
}
render (props) {
const {contentStrings} = this.props.config
return (
<div>
//Should only allow the modal to show if the username is the same as the email or there is no username available
{ props.displayNameModalActive && this.state.displayName === this.state.email || !this.state.displayName &&
<div className='display-name-container' style={{ backgroundImage: `url(${this.props.bgImgUrl})` }}>
<div className='display-name-content'>
<h2 className='heading'>{contentStrings.displayNameModal.heading}</h2>
<p>{contentStrings.displayNameModal.subHeading}</p>
<input type="text"
defaultValue={this.state.displayName}
placeholder={this.state.displayName}
minLength="3"
maxLength="15"/>
<button
onClick={this.updateDisplayName}
className='btn btn--primary btn--md'>
<span>{contentStrings.displayNameModal.button}</span>
</button>
<p className='cancel'>{contentStrings.displayNameModal.cancel}</p>
</div>
</div>
}
</div>
)
}
}
export default DisplayNameModal
Whyt this:
props.displayNameModalActive
and not this:
this.props.displayNameModalActive
?
Correct me if I'm wrong but render doesn't get props as argument.
So I am organizing my React project and I am creating a form, which I would like to give the user the ability to individually edit and post values for a particular item in the form, or alternatively check a box that will let them edit multiple fields at once, and hit a save button to load the whole form. So I know my parent component is going to need an "isEditingAll" type of state and my child components (each field) will have to display their own "isEditing" state for when it can save its value up as an individual post. Currently I have the following code in the render of my child:
render(){
return(
<span className="displayList">
{this.state.isEditing ? '' : <span className="clickMe" onClick={this.onClickEdit}>{this.state.displayText}</span>}
{this.state.isEditing ? <span><input name="inputValue" className="inputValue" value={this.state.displayText} type="text" onKeyPress={this.handleKeyPress} onChange={this.onTextChanged}/></span> :''}
{this.state.isEditing ? <button className="saveMe" onClick={this.onSaveEdit}>Save</button> :''}
</span>
)
}
This allows me to view values when !isEditing and edit values when isEditing, and there is a save button. But when someone checks the box in a parent, I need it to override this value. Is the best option to add a prop value that is passed in from the parent state for isEditingAll prop that will connect my parent isEditingAll? Then I would be able to hide the save button when editing entire form. I just fear I am adding a lot of complexity to the child component. Let me know your thoughts and if I may be missing some possible options for this logic? Thanks in advance.
No problem, you can do it if you need.
Reactjs is a very flexible library that allows developer do lots of crazy things.
In this scenario, I was imagining you could do something like this.
MainForm.js
import React, { Component } from 'react';
import InputForm from './InputForm';
class MainForm extends Component {
constructor(props) {
super(props);
this.state = {
multipleChecked: false,
fields: [{name: 'name', value: 'Alfred'}, {name: 'lastName', value: 'Smith'}],
}
}
onMultipleClick(e) {
this.setState({multipleChecked: e.target.checked});
}
onSaveIndividualEdit(name, value) {
let fieldsChanged = this.state.fields;
fieldsChanged.forEach(field => {
if (name == field.name) {
field.value = value;
return true;
}
});
this.setState({fields: fieldsChanged});
}
render() {
return (
<div>
<input type="checkbox" onClick={this.onMultipleClick.bind(this)}>Multiple edit</input>
{this.state.fields.map(field =>
<InputForm editingMultiple={this.state.multipleChecked} name={field.name} value={field.value} onSaveIndividualEdit={this.onSaveIndividualEdit.bind(this)} />
)}
</div>
);
}
}
export default MainForm;
InputForm.js
import React, { Component, PropTypes } from 'react';
class InputForm extends Component {
constructor(props) {
super(props);
this.state = {
isEditing: false,
editingMultiple: false,
displayText: ''
}
}
componentWillReceiveProps(nextProps) {
if (nextProps !== undefined) {
if (nextProps['value'] !== undefined) {
this.setState({displayText: nextProps.value});
}
if (nextProps['isEditing'] !== undefined) {
this.setState({isEditing: nextProps.isEditing});
}
if (nextProps['editingMultiple'] !== undefined) {
this.setState({editingMultiple: nextProps.editingMultiple});
}
}
}
onTextChanged(e) {
this.setState({displayText: e.target.value});
}
onClickEdit() {
this.setState({isEditing: true});
}
onSaveEdit() {
this.props.onSaveEdit(this.props.name, this.state.displayText);
this.setState({isEditing: false});
}
render() {
return (
<div>
<span className="displayList">
{this.state.isEditing ? '' : <span className="clickMe" onClick={() => this.onClickEdit()}>{this.state.displayText}</span>}
{this.state.isEditing ? <span><input type="text" onChange={this.onTextChanged.bind(this)} value={this.state.displayText}/></span> :''}
{this.state.isEditing && !this.state.editingMultiple ? <button type="button" onClick={() => this.onSaveEdit()}>Save</button> :''}
</span>
</div>
);
}
}
InputForm.propTypes = {
name: PropTypes.string,
value: PropTypes.string,
editingMultiple: PropTypes.bool,
onSaveEdit: PropTypes.func
};
export default InputForm;
I hope it can help you to make you go ahead!
Regards,
Renan