Displaying Div with Child and Parent state values - reactjs

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

Related

React radio buttons wont change

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}
//...
/>

How to render react component onClick?

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.

React. Formsy-react and checkboxes

In my react app I have generic Input component:
class Input extends Component {
constructor(props) {
super(props);
if (props) {
this.state = {
elementType: props.elementType,
elementConfig: props.elementConfig,
cssClasses: props.cssClasses,
};
}
this.changeValue = this.changeValue.bind(this);
}
render() {
switch (this.state.elementType) {
case ('input'):
inputElement = <input
className={inputClasses.join(' ')}
{...this.state.elementConfig}
value={this.props.getValue() || ''}
onChange={this.changeValue} />;
break;
}
return (
<div className={requiredClass}>
{inputElement}
<span className={'text-danger'}>{requiredMessage}</span>
<span className={'text-danger'}>{errorMessage}</span>
</div>
);
}
}
Next, I use this group of inputs with react-formsy:
<Formsy>
<Input
requiredMessage='required'
required
name="checkbox"
elementType="input"
elementConfig={{ type: 'checkbox', id: 'check1'}}
cssClasses={['custom-input']}
/>
<button type="button" disabled={!this.props.canSubmit}></button>
</Formsy>
This checkboxes should be required,
until they are checked, the button must be inactive.
but the problem is that I can't check the checkboxes.
I am new in react. Where is my mistake?

Adding an active class to a react element to be able to change css

What I want to do is to be able to toggle an active class on my elements that are dynamically created, as to be able to change the css for the selected checkbox, giving the impression that a certain filter is selected. I have looked at so many solutions and guides to make this work for my app, but I can't seem to implement it correctly. Any help would be appreciated.
Checkboxes component
import React from 'react';
const Checkbox = (props) => {
const { label, subKey } = props;
const sub1 = `${subKey}1`;
return (
<label htmlFor={sub1} className="check_label">
{label}
<input
type="checkbox"
id={sub1}
checked={props.isChecked}
onChange={props.handleCheck}
onClick={() => console.log(label)}
value={`${label.toLowerCase()}/?search=`}
/>
</label>
);
};
export default Checkbox;
and the Search component that implements checkboxes
import React, { Component } from 'react';
import Checkbox from './Checkbox';
const APIQuery = 'https://swapi.co/api/';
const searchLabels = ['Planets', 'Starships', 'People', 'Species', 'Films', 'Vehicles'];
export default class Searchbutton extends Component {
constructor(props) {
super(props);
this.state = {
endpointValue: '',
searchValue: '',
};
}
/* Funcionality to handle form and state of form */
/* Changes state of value whenever the form is changed, in realtime. */
handleChange(event) {
this.setState({ searchValue: event.target.value });
}
/* Prevents default formsubmit */
handleSubmit(event) {
event.preventDefault();
}
/* Handles state of checkboxes and sets state as to prepend necessary filter for request */
handleCheck(event) {
this.setState({ endpointValue: event.target.value });
if (this.state.endpointValue === event.target.value) {
this.setState({ endpointValue: '' });
}
}
/* Creates the checkboxes dynamically from the list of labels. */
createBoxes() {
const checkboxArray = [];
searchLabels.map(item => checkboxArray.push(
<Checkbox
key={item}
className="madeBoxes"
subKey={item}
endpointValue={this.state.endpointValue}
handleChange={e => this.handleChange(e)}
handleCheck={e => this.handleCheck(e)}
label={item}
/>,
));
return checkboxArray;
}
render() {
return (
<div className="search_content">
<div className="search_wrapper">
<form onSubmit={this.handleSubmit} method="#">
<label htmlFor="searchBar">
<input type="text" id="searchbar" className="search_bar" value={this.state.searchValue} onChange={e => this.handleChange(e)} />
</label>
<div>
<input type="submit" className="search_button" value="May the Force be with you." onClick={() => this.props.searchWithApi(APIQuery + this.state.endpointValue + this.state.searchValue)} />
</div>
</form>
</div>
<div className="checkboxes">
{this.createBoxes(this.labels)}
</div>
<div className="sort_filters">
{' '}
{/* These are options that the user can make in order to sort and filter the results.
The idea is to make it so that changing the value auto-perform a new request */}
{/* For sorting the returned objects based on user choice */}
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid, until href added */}
Choose sort method
<ul className="sorting">
<li className="sort_optn" href="#" value="lexicographical">Alphabetically</li>
<li className="sort_optn" href="#" value="by_added_date">By added date</li>
<li className="sort_optn" href="#" value="by_added_date_rev">By added date reversed</li>
</ul>
</div>
</div>
);
}
}
You don't really have to do it with react. You can reformat your code a little bit and solve it with CSS :checked pseudo-class.
In particular, don't wrap your checkbox within a label, but instead put the label after the input. Check this fiddle for example: https://jsfiddle.net/8c7a0fx5/
You can use the styled-component package. check the example below on how to use it:
import { Component } from 'react'
import { render } from 'react-dom'
import styled from 'styled-components'
const StyledCheckbox = styled.div`
label {
background: ${props => props.active ? 'red': 'white'}
}
`
class MyAwesomeComponent extends Component {
constructor(){
super()
this.state = {
isChecked: false
}
this.handleOnChange = this.handleOnChange.bind(this)
}
handleOnChange = ()=>{
this.setState({
isChecked: !this.state.isChecked,
})
}
render(){
const { isChecked } = this.state
return(
<StyledCheckbox active={isChecked}>
<label>Names</label>
<input type="checkbox" onChange={this.handleOnChange} />
</StyledCheckbox>
)
}
}
render(<MyAwesomeComponent/>, document.getElementById('root'))
Working code on codepen.io

Input lost focus when I type a word into in React

I'm making a React component including a <input type="text"> component. The problem is when I typed a word, the <input> lost its focus, I have to click it again and type again and lost focus again...
I used a custom <InputText> component, set its value via value props and get its changed value via onChanged props which is a function.
I used this method many times but have no idea it doesn't work now.
Below is my main component:
import React from 'react';
import uniqueid from 'lodash.uniqueid';
import InputText from '../shared/InputText';
class EditCategories extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
categories: [
{"category": 1},
{"category": 2},
],
num: 2,
};
}
render () {
return(
<div id="categories">
{this.renderCategoryInput()}
</div>
);
}
renderCategoryInput() {
let categoryInputList = [];
let i = 0;
while(i < this.state.num) {
categoryInputList.push(
<div className="form-group" key={uniqueid('key-')}>
<label className="col-sm-2 control-label">Cat {i + 1}</label>
<div className="col-sm-4">
<InputText
field='category'
type='text'
id={uniqueid('category-')}
className='form-control'
value={(this.state.categories[i]) ? this.state.categories[i].category : ''}
onChanged={this.handleChange.bind(this, i)}
/>
</div>
<span
className="glyphicon glyphicon-plus"
onClick={this.addCategoryInput.bind(this)}>
</span>
<span
className="glyphicon glyphicon-minus"
onClick={this.removeCategoryInput.bind(this, i)}>
</span>
</div>
);
i++;
}
return categoryInputList;
}
handleChange(i, key, value) {
let categories = this.state.categories;
if(!categories[i]) {
categories[i] = {};
}
categories[i][key] = value;
this.setState({categories: categories});
console.log(this.state.categories);
}
removeCategoryInput(i) {
let categories = (this.state.categories) ? this.state.categories : [];
categories.splice(i,1);
this.setState({num: this.state.num - 1});
this.setState({categories: categories});
this.props.onChanged(categories, categories);
}
addCategoryInput() {
this.setState({num: this.state.num + 1});
}
};
EditCategories.contextTypes = {
data: React.PropTypes.object.isRequired
};
export default EditCategories;
Below is the <InputText> component:
import React from 'react';
class InputText extends React.Component {
constructor(props, context) {
super(props, context);
}
render () {
return(
<input
type={this.props.type}
id={this.props.id}
className={this.props.className}
value={this.props.value}
placeholder={(this.props.placeholder) ? this.props.placeholder : ''}
onChange={this.handleChange.bind(this)}
/>
);
}
handleChange(ev) {
this.props.onChanged(this.props.field, ev.target.value);
}
};
InputText.propTypes = {
field: React.PropTypes.string.isRequired,
type: React.PropTypes.string.isRequired,
onChanged: React.PropTypes.func.isRequired,
id: React.PropTypes.string,
value: React.PropTypes.string,
className: React.PropTypes.string,
placeholder: React.PropTypes.string,
};
InputText.contextTypes = {
data: React.PropTypes.object.isRequired
};
export default InputText;
No console error/warnning, I can log the changed this.state.categories and everything looks just fine.
Can anyone help?
I finally found that the problem is the key property. Because I used uniqueid() to generate the key, it's different in every time rendering. After changing it to static value, everything is fine.
Another potential problem may caused by uniqueid() function is that if generate the id by it, then the server rendering result may be different with the client rendering result, then you will get a React attempted to reuse markup in a container but the checksum was invalid warining

Resources