Checkboxes - Getting starting value from state - javascript

I have the following form, and the part that works is it sets the state for each option to "true" of "false" as I check and uncheck the boxes as expected.
My problem is that when I first run the app, if I have some states set to true, I want those checkboxes to start off rendered as checked... however they don't. Even those the state is true, they all render unchecked. I believe I'm just not getting the value to the right spot to make it check. But I'm not sure what else to try. Any help would be appreciated.
Parent Component:
class Audit extends Component {
constructor(props) {
super(props);
this.state = {
formRewardsService: true,
formRewardsRetirement: true,
formRewardsPeerRecognition: false,
formRewardsSpot: false
};
this.handleCheck = this.handleCheck.bind(this);
}
handleCheck(e) {
this.setState(({ isChecked }) => (
{
isChecked: !isChecked
}
));
console.log(e.target.name + ': ' + e.target.checked);
}
render() {
return (
<ThemeProvider theme={theme}>
<Container>
<Div>
<Tabs defaultActiveKey="general" id="audit=tabs">
<Tab eventKey="culture" title="Culture">
<Culture handleCheck={this.handleCheck} { />
</Tab>
</Tabs>
</Div>
</Container>
</ThemeProvider>
);
}
}
export default Audit;
My Child Component with the form and checkboxes(The first two should render as checked since they are "true" to start off):
import React, { Component } from 'react';
import {Container, Form, Row, Col} from 'react-bootstrap';
import styled, { ThemeProvider } from 'styled-components';
import theme from "../../../../Config/Theme";
const Div = styled.div`
background-color: white;
color: black;
`
class Culture extends Component {
render() {
return (
<ThemeProvider theme={theme}>
<Div>
<Container >
<Form className="p-3">
<Form.Group name="formRewards1" as={Row} controlId="formRewards1" onChange={this.props.handleCheck}>
<Form.Label column sm={5}>
1.What types of employee recognition programs are utilized within the organization? Check all that apply.
</Form.Label>
<Col>
<Form.Check
type="checkbox"
label="Service Awards"
value={this.props.formRewardsService}
name="formRewardsService"
id="formRewards1-1"
checked={this.props.value}
/>
<Form.Check
type="checkbox"
label="Retirement Awards"
value={this.props.formRewardsRetirement}
name="formRewardsRetirement"
id="formRewards1-2"
checked={this.props.value}
/>
<Form.Check
type="checkbox"
label="Peer Recognition Awards"
value={this.props.formRewardsPeer}
name="formRewardsPeer"
id="formRewards1-3"
checked={this.props.value}
/>
<Form.Check
type="checkbox"
label="Spot Awards"
value={this.props.formRewardsSpot}
name="formRewardsSpot"
id="formRewards1-4"
checked={this.props.value}
/>
</Col>
</Form.Group>
</div>
</Form>
</Container>
</Div>
</ThemeProvider>
);
}
}
export default Culture;

To pass all checkboxes value from state at once, you can grab them in a sub level of state like:
state = { checkboxes : {
formRewardsService: false,
formRewardsRetirement : true,
...
}}
and then pass only checkboxes states to Culture props
<Culture handleCheck={this.handleCheck} {...this.state.checkboxes } />
And rewrite your handleCheck function like this:
handleCheck = (e) => {
const name = e.target.name;
const checked = e.target.checked
this.setState(
{
...this.state,
checkboxes: {
...this.state.checkboxes,
[name]: checked
}
}
));
console.log(e.target.name + ': ' + e.target.checked);
}

You can remove the bind function if you write function like this:
handleCheck = (e) => { ...
Then write this function to set the state properly like this:
handleCheck = (e) => {
const name = e.target.name;
const checked = e.target.checked
this.setState(
{
[name]: checked
}
));
console.log(e.target.name + ': ' + e.target.checked);
}
Then you have to pass checked states to Culture props.
render() {
return (
<ThemeProvider theme={theme}>
<Container>
<Div>
<Tabs defaultActiveKey="general" id="audit=tabs">
<Tab eventKey="culture" title="Culture">
<Culture handleCheck={this.handleCheck} formRewardsService={this.state.formRewardsService} ... />
</Tab>
</Tabs>
</Div>
</Container>
</ThemeProvider>
);
}
and for checkboxes:
<Form.Check
type="checkbox"
label="Service Awards"
name="formRewardsService"
id="formRewards1-1"
checked={this.props.formRewardsService}
/>

Related

Updating state from child component to parent component

I'm struggling with an issue of App.js which has a Checkboxes component. When someone ticks a checkbox in that component, I want the state for that checkbox to be updated in the App.js file. The code for my Checkboxes component is below. I am using material ui if that makes any difference.
import Checkbox from '#material-ui/core/Checkbox';
import FormGroup from '#material-ui/core/FormGroup';
import FormControlLabel from '#material-ui/core/FormControlLabel';
export default function CheckboxLabels() {
return (
<FormGroup row>
<FormControlLabel
control={<Checkbox name="checkedD" />}
label="Remove Duplicates"
/>
</FormGroup>
);
}
The code in App.js that is relevant is:
<Grid>
<Checkboxes />
</Grid>
What should I be doing? How do I modify the above code?
If you want to keep the state in the App component, then you need to pass a function to your child component which will be used to send the state to the parent (App) component.
In your parent component, you would create the state so that each state of checkboxes can be stored and pass the function that will handle the updating of the state. I would store the state in Map to avoid having duplications of the same checkbox on each update. Also, pass an id to each of the Checkbox components so that you know which state refers to which checkbox when updating later on.
import React from "react";
import CheckboxLabels from "./CheckboxLabel";
class App extends React.Component {
state = {
checkboxes: new Map()
};
handleClick = (e, id) => {
const { checked } = e.target;
this.setState((prevState) => ({
checkboxes: prevState.checkboxes.set(id, checked)
}));
};
render() {
return (
<div className="App">
<CheckboxLabels id={1} handleClick={this.handleClick} />
<CheckboxLabels id={2} handleClick={this.handleClick} />
<CheckboxLabels id={3} handleClick={this.handleClick} />
<CheckboxLabels id={4} handleClick={this.handleClick} />
</div>
);
}
}
export default App;
In your child component, you would accept the function and the id and then pass that function with the event and id in onChange method of the checkbox.
import React from "react";
import Checkbox from "#material-ui/core/Checkbox";
import FormGroup from "#material-ui/core/FormGroup";
import FormControlLabel from "#material-ui/core/FormControlLabel";
export default function CheckboxLabels({ id, handleClick }) {
return (
<FormGroup row>
<FormControlLabel
control={<Checkbox name="checkedD" />}
label="Remove Duplicates"
onChange={(e) => handleClick(e, id)}
/>
</FormGroup>
);
}
This way, you can store the state of multiple checkboxes and you can easily track which state is which by an id.
You can use regular state mechanism in parent and just pass it down to CheckboxLabels component. So send setChecked and checked values down:
export default function CheckboxLabels({ checked, onChange }) {
return (
<FormGroup row>
<FormControlLabel
control={
<Checkbox
name="checkedD"
checked={checked}
onChange={(e) => {
if (onChange) {
onChange(e.target.checked);
}
}}
/>
}
label="Remove Duplicates"
/>
</FormGroup>
);
}
export default function App() {
const [checked, setChecked] = useState(false);
return (
<Grid>
<CheckboxLabels checked={checked} onChange={setChecked} />
</Grid>
);
}
I am not sure if your code is good naming-wise, but I added that checkbox component is name CheckboxLabels

React Conditional Rendering of Component Inside Function Not Working

I am using Codesandbox to work on learning React. I am trying to conditionally render a functional React component inside of a function (inside of a class based component), that fires when a button is clicked.
Here is the link to the Codesandbox: https://codesandbox.io/embed/laughing-butterfly-mtjrq?fontsize=14&hidenavigation=1&theme=dark
The issue I have is that, without importing and rendering the Error and Meals in App.js, I never can get either component to render from the Booking component. In the function here:
if (!this.state.name) {
return (
<div>
<Error />
</div>
);
}
else {
return <Meals name={this.state.name} date={this.state.date} />;
}
}
I should be rendering Error, which should then show on the screen on click if no name is inputted but nothing happens and I am stumped.
Is there anything obvious that would be preventing me from seeing the Error component from loading on the click?
Thank you in advance!
Everything that is displayed on the screen comes from render method. You cann't return JSX from any function like that. You can do something like this:
class Bookings extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
date: "",
display: false
};
}
guestInfoHandler = event => {
console.log(this.state, "what is the state");
this.setState({ name: event.target.value });
};
dateInfoHandler = event => {
this.setState({ date: event.target.value });
};
showMeals = () => {
this.setState({ display: true });
};
render() {
return (
<>
<div style={{ display: "inline-block" }}>
<form
className="theForm"
style={{
height: "50px",
width: "100px",
borderColor: "black",
borderWidth: "1px"
}}
>
<label className="theLabel">
Name:
<input
className="theInput"
type="text"
placeholder="guest name here"
onChange={this.guestInfoHandler}
value={this.state.value}
/>
</label>
</form>
<form>
<label>
Date:
<input
type="text"
placeholder="date here"
onChange={this.dateInfoHandler}
value={this.state.value}
/>
</label>
</form>
<button onClick={() => this.showMeals()}>Click</button>
</div>
{ display && name ? (
<Meals name={name} date={name} />
) : (
<Error />
)}
</>
);
}
}
export default Bookings;
Hope this works for you.
render() {
const name = this.state.name;
return (
<div>
{name ? (
<Meals name={name} date={name} />
) : (
<Error />
)}
</div>
);
}
nb:use render method in class component only.
there is various types conditional rendering mentioned in
https://reactjs.org/docs/conditional-rendering.html#

How to pass props to one React Class to Another React Class?

I am trying to have a button enabled in a modal when text is entered in an input field. But my form is built in another class and is used in a parent class. How can I pass an onChange method my form component.
Here is my parent component:
import React from 'react';
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle
} from '#material-ui/core';
import CompanyFinancialModalForm from '../CompanyFinancialModalForm/CompanyFinancialModalForm';
interface CompanyFinancialModalState {
addEnabled: boolean;
}
interface CompanyFinancialModalProps {
open: boolean;
onClose: () => void;
}
export class CompanyFinancialModal extends React.Component<
CompanyFinancialModalProps,
CompanyFinancialModalState
> {
constructor(props: CompanyFinancialModalProps) {
super(props);
this.state = {
addEnabled: false
};
}
private enableButton = () => {
this.setState({ addEnabled: true});
}
public render() {
const { open, onClose } = this.props;
const { addEnabled } = this.state;
return (
<>
<Dialog
open={open}
onClose={onClose}
className="company-financial-modal"
>
<DialogTitle id="company-financial-modal-title">
{'Company and Financial Data'}
</DialogTitle>
<DialogContent>
<CompanyFinancialModalForm onChange={this.enableButton}/>
</DialogContent>
<DialogActions>
<Button
id="company-financial-modal-add"
disabled={!addEnabled}
onClick={onClose}
color="primary"
>
Add
</Button>
<Button
id="company-financial-modal-cancel"
onClick={onClose}
color="secondary"
autoFocus={true}
>
Cancel
</Button>
</DialogActions>
</Dialog>
</>
);
}
}
export default CompanyFinancialModal;
Here is my class that my form is in:
import React from 'react';
import axios from 'axios';
import { Form, Field } from 'react-final-form';
import { TextField, Select } from 'final-form-material-ui';
import {
Paper,
Grid,
MenuItem,
} from '#material-ui/core';
export interface IValues {
company_name: string;
critical_technology: [];
}
export interface IFormState {
[key: string]: any;
values: IValues[];
submitSuccess: boolean;
}
export default class CompanyFinancialModalForm extends React.Component<{}, IFormState> {
constructor(props: {}) {
super(props);
this.state = {
company_name: '',
critical_technology: [],
values: [],
submitSuccess: false
};
}
private processFormSubmission = (e: React.FormEvent<HTMLFormElement>): void => {
e.preventDefault();
this.setState({ loading: true });
const formData = {
company_name: this.state.company_name,
critical_technology: this.state.critical_technology
};
this.setState({
submitSuccess: true,
values: [...this.state.values, formData],
loading: false
});
axios.post(`http://localhost:8081/companies`, formData);
}
private onChange = (e: React.FormEvent<HTMLInputElement>) => {
const { name, value } = e.target;
// other form-related logic
this.props.onChange({ name, value }, e);
}
public render() {
const { submitSuccess, loading } = this.state;
const { onChange } = this.props;
return (
<div>
<Form
onSubmit={this.processFormSubmission}
// validate={this.validateForm}
render={({ handleSubmit,/* reset, submitting, pristine, values*/ }) => (
<form onSubmit={handleSubmit} noValidate>
<Paper style={{ padding: 16 }}>
<Grid container alignItems="flex-start" spacing={2}>
<Grid item xs={6}>
<Field
fullWidth
required
name="companyName"
component={TextField}
type="text"
label="Company Name"
onChange={onChange}
/>
</Grid>
<Grid item xs={12}>
<Field
name="critical_technology"
label="Critical Technology"
component={Select as any}
>
<MenuItem value="hypersonics">Hypersonics</MenuItem>
<MenuItem value="directed_energy">Directed Energy</MenuItem>
<MenuItem value="command_control_and_communications">Command, Control and Communications </MenuItem>
<MenuItem value="space_offense_and_defense">Space Offense and Defense</MenuItem>
<MenuItem value="cybersecurity">Cybersecurity</MenuItem>
<MenuItem value="artificial_intelligence_machine_learning">Artificial Intelligence/Machine Learning</MenuItem>
<MenuItem value="missile_defense">Missile Defense</MenuItem>
<MenuItem value="quantum_science_and_computing">Quantum Science and Computing </MenuItem>
<MenuItem value="microelectronics">Microelectronics</MenuItem>
<MenuItem value="autonomy">Autonomy</MenuItem>
</Field>
</Grid>
</Grid>
</Paper>
</form>
)}
/>
</div>
);
}
}
I want to pass a prop to <CompanyFinancialModalForm /> that enables the add button when the Textfield has text typed into it.
For future reference, it will be more beneficial if you only include the relevant code, because it takes more time to find when scrolling through irrelevant code, anyways:
I'm not 100% clear on what you're looking for, but I'll try to answer what I think I understand. You can add an onChange method on your parent component, and pass that as a prop to the form, and the form can call that function every time it runs it's own onChange method. Below is a simplified version:
class Parent extends Component {
state = {
buttonEnabled: false,
// formInputValue: '', <-- if you need this
};
// - omitting constructor/bind for simplicity for now
onChange({ name, value }, e) {
// your logic to determine whether button is enabled or not
// this is just me guessing what you want to implement
if (value) this.setState({ buttonEnabled: true });
else this.setState({ buttonEnabled: false });
}
render() {
return (
<Fragment>
<YourForm onChange={this.onChange} />
<Button enabled={this.state.buttonEnabled} />
</Fragment>
);
}
}
class YourForm extends Component {
onChange(e) {
const { name, value } = e.target;
// other form-related logic
this.props.onChange({ name, value }, e);
}
}
is this what you're looking for?
You can simply pass a child a reference to a function that exists in the parent and then use the parent's function to validate and enable the button.
Codesandbox Demo
Simplified Code:
function Child (props) {
return (
<input type="text" onChange={props.doIt}/>
)
}
function App() {
const [disabled, setDisabled] = useState(true);
function doIt(e) {
setDisabled(e.currentTarget.value.length === 0);
}
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<Child doIt={doIt} />
<button disabled={disabled}>Add</button>
</div>
);
}

React JS Warnings: Failed propType and uncontrolled input

I'm struggling to fix some issues regarding React JS. Currently worked on a crash course, and I've been trying to improve the todoList. I'm very new and hopefully this might give me a new perspective after already 8 hours of troubleshooting.
My code - Input:
export class TodoItem extends Component {
getStyle = () => {
return {
background: '#233D4D',
padding: '15px',
borderBottom: '1px darkgray Ridge',
textDecoration: this.props.todo.completed ? 'line-through' :
'none',
color: this.props.todo.completed ? 'lightgreen' : 'white',
fontWeight: this.props.todo.completed ? 'bold' : 'none',
}
}
render() {
const { title } = this.props.todo;
return (
<div style={this.getStyle()}>
<p>
<input type="checkbox" onChange= .
{this.props.markComplete.bind(this)} checked= .
{this.props.todo.completed} /> {' '}
{title}
<button style={btnStyle} onClick= .
{this.props.delTodo.bind(this)}><FontAwesomeIcon size="2x" icon= .
{faTrash} /></button>
</p>
</div>
)
}
}
// PropTypes
TodoItem.propTypes = {
Todos: PropTypes.array.isRequired,
markComplete: PropTypes.func.isRequired,
delTodo: PropTypes.func.isRequired
}
My code - Failed propType:
render() {
const { title } = this.props.todo;
return (
<div style={this.getStyle()}>
<p>
<input type="checkbox"
onChange={this.props.markComplete.bind(this)}
checked={this.props.todo.completed} /> {' '}
{title}
<button style={btnStyle}
onClick={this.props.delTodo.bind(this)}>
<FontAwesomeIcon size="2x" icon={faTrash} />
</button>
</p>
</div>
)
}
// PropTypes
TodoItem.propTypes = {
Todos: PropTypes.array.isRequired,
markComplete: PropTypes.func.isRequired,
delTodo: PropTypes.func.isRequired
}
Heres my issues:
#1 - Prop Types
index.js:1446 Warning: Failed prop type: The prop `Todos` is marked as required in `TodoItem`, but its value is `undefined`.
in TodoItem (at Todos.js:12)
#2 - Component changing an uncontrolled input
Warning: A component is changing an uncontrolled input of type text to
be controlled. Input elements should not switch from uncontrolled to
controlled (or vice versa). Decide between using a controlled or
uncontrolled input element for the lifetime of the component.`
======== EDIT =========
Heres where the components called, properties passed and the manipulation:
render() {
return (
<Router>
<div className="App">
<div className="container">
<Header />
<Route exact path="/" render={props => (
<React.Fragment>
<AddTodo addTodo={this.addTodo} />
<Todos todos={this.state.todo} markComplete= .
{this.markComplete}
delTodo={this.delTodo} />
</React.Fragment>
)} />
<Route path="/about" component={About} />
</div>
</div>
</Router>
);
class Todos extends Component {
render() {
// Mangler håndtering af ingen elementer
let output = undefined;
if(this.props.todos && this.props.todos.length > 0){
// lav object
let output = this.props.todos.map((todo) => (
<TodoItem key={todo.id} todo={todo} markComplete=
{this.props.markComplete} delTodo={this.props.delTodo} />
))
return output;
}
return (
<div>
{output}
</div>
/*this.props.todos.map((todo) => (
<TodoItem key={todo.id} todo={todo} markComplete=
{this.props.markComplete} delTodo={this.props.delTodo} />
))*/
);
}
}
I cleaned the mess in your code a bit and it is now working for me:
const TodoItem = ({title, completed, delTodo, markComplete}) => (
<div>
<p>
<input type="checkbox" onChange={markComplete} checked={completed} />
{title}
<button onClick={delTodo}>Delete</button>
</p>
</div>
);
TodoItem.propTypes = {
title: PropTypes.string.isRequired,
completed: PropTypes.bool.isRequired,
markComplete: PropTypes.func.isRequired,
delTodo: PropTypes.func.isRequired
};
class Todos extends Component {
constructor(props) {
super(props);
this.state = {
todos: [
{id: 1, title: "First", completed: false},
{id: 2, title: "Second", completed: false},
{id: 3, title: "Third", completed: true}
]
};
}
markComplete = id => {
const index = this.state.todos.findIndex(t => t.id === id);
if (index > -1) {
const modifiedTodos = JSON.parse(JSON.stringify(this.state.todos));
modifiedTodos[index].completed = true;
this.setState({todos: modifiedTodos});
}
};
delTodo = id => {
const index = this.state.todos.findIndex(t => t.id === id);
if (index > -1) {
const modifiedTodos = JSON.parse(JSON.stringify(this.state.todos));
modifiedTodos.splice(index, 1);
this.setState({todos: modifiedTodos});
}
};
render() {
return (
<div>
{this.state.todos
? this.state.todos.map(todo => (
<TodoItem
key={todo.id}
title={todo.title}
completed={todo.completed}
markComplete={() => this.markComplete(todo.id)}
delTodo={() => this.delTodo(todo.id)}
/>
))
: null}
</div>
);
}
}
Some comments about your code:
[FIRST ERROR]: Via propTypes you had Todos as property for TodoItem, but you didn't set that property when using TodoItem and because you set it as required with .isRequired, the first error had been thrown.
[SECOND ERROR]: As far as I can tell, changing from uncontrolled to controlled inputs happens, when the change handler changes from undefined to some function. You didn't paste your code with that function, so I can not tell, what was going wrong exactly, but I think the problem is the binding of the functions markComplete and delTodo you provided TodoItem via prop. Usually this binds the this object to the current execution context (class TodoItem in this case) and because TodoItem has no member functions markComplete and delTodo itself, the binding returns undefined for them.
Next time you post a question try to write a minimal working example (MWE). Your code is really bloated with irrelevant stuff. Remove that and the folks here at SO will have a much better time helping you.
In your classes Todos and TodoItem you don't have any state, so better use stateless function components (much more compact).
On some places you had white spaces and dots separating your property names and your property values.

React JS Sortable Form Fields as Components

I'm trying to develop a fairly simplistic E-Mail template creator with React JS. I'm using the "react-sortable-hoc" library as a means to handle the ordering of elements on the page.
The goal is to allow users to create "Rows", rearrange rows, and within each row, have multiple "Columns" that can contain components like images, textboxes, etc...
But I keep running into the same issue with Sortable libraries. Form fields cannot maintain their own "state" when being dragged up or down. The State of a Component in React JS seems to be lost when it's in a draggable component. I've experienced similar issues with JQuery UI's Sortable but it required an equally ridiculous solution. Is it common to find that form fields are simply super difficult to rearrange?
As a "proof of concept", I am using a complex JSON object that stores all the information in the Letter.js component and passes it down as Props which are then passed down to each component. But as you can tell, this is becoming cumbersome.
Here is an example of my Letter component that handles the JSON object and sorting of Rows:
import React, {Component} from 'react';
import {render} from 'react-dom';
import {
SortableContainer,
SortableElement,
arrayMove
} from 'react-sortable-hoc';
import Row from './Row';
const SortableItem = SortableElement(({row, rowIndex, onChange, addPart}) => {
return (
<li>
<Row
row={row}
rowIndex={rowIndex}
onChange={onChange}
addPart={addPart} />
</li>
)
});
const SortableList = SortableContainer(({rows, onChange, addPart}) => {
return (
<ul id="sortableList">
{rows.map((row, index) => {
return (
<SortableItem
key={`row-${index}`}
index={index}
row={row}
rowIndex={index}
onChange={onChange}
addPart={addPart}
/> )
})}
</ul>
);
});
class Letter extends Component {
constructor(props) {
super(props);
this.state = {
rows: [],
}
this.onSortEnd = this.onSortEnd.bind(this);
this.onChange = this.onChange.bind(this);
this.addRow = this.addRow.bind(this);
this.addPart = this.addPart.bind(this);
}
addPart(event, index, value, rowIndex, columnIndex) {
console.log(value);
var part = {};
if(value === 'Text') {
part = {
type: 'Text',
value: ''
}
} else if(value === 'Image') {
part = {
type: 'Image',
value: ''
}
} else {
part = {
type: 'Empty',
}
}
const { rows } = this.state;
rows[rowIndex][columnIndex] = part;
this.setState({ rows: rows })
}
onChange(text, rowIndex, columnIndex) {
const { rows } = this.state;
const newRows = [...rows];
newRows[rowIndex][columnIndex].value = text;
this.setState({ rows: newRows });
}
addRow(columnCount) {
var rows = this.state.rows.slice();
var row = [];
for(var i = 0; i < columnCount; i++) {
var part = {
type: 'Empty',
}
row.push(part);
}
rows.push(row);
this.setState({ rows: rows })
}
onSortEnd = ({oldIndex, newIndex}) => {
this.setState({
rows: arrayMove(this.state.rows, oldIndex, newIndex),
});
};
render() {
console.log(JSON.stringify(this.state.rows));
const SideBar = (
<div className="sideBar">
<h3>Add a Row</h3>
<button className="uw-button" onClick={() => this.addRow(1)}>1 - Column</button><br/><br/>
<button className="uw-button" onClick={() => this.addRow(2)}>2 - Column</button><br/><br/>
<button className="uw-button" onClick={() => this.addRow(3)}>3 - Column</button>
<hr />
</div>
);
if(this.state.rows.length <= 0) {
return (
<div className="grid">
<p>This E-Mail is currently empty! Add some components to make a template.</p>
{SideBar}
</div>
)
}
return (
<div className="grid">
<SortableList
rows={this.state.rows}
onChange={this.onChange}
addPart={this.addPart}
lockAxis="y"
useDragHandle={true}
onSortStart={this.onSortStart}
onSortMove={this.onSortMove}
onSortEnd={this.onSortEnd}
shouldCancelStart={this.shouldCancelStart} />
{SideBar}
</div>
);
}
}
export default Letter;
And here is an example of Row:
import React, { Component } from 'react';
import { Text, Image } from './components/';
import { SortableHandle } from 'react-sortable-hoc';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import { Card, CardActions, CardHeader, CardMedia, CardTitle, CardText } from 'material-ui/Card';
import DropDownMenu from 'material-ui/DropDownMenu';
import MenuItem from 'material-ui/MenuItem';
const DragHandle = SortableHandle(() => <span className="dragHandle"></span>);
class Row extends Component {
constructor(props) {
super(props);
}
render() {
if(this.props.row !== undefined && this.props.row.length > 0) {
const row = this.props.row.map((column, columnIndex) => {
if(column.type === 'Empty') {
return (
<MuiThemeProvider key={columnIndex}>
<div className="emptyColumn">
<Card>
<DragHandle />
<CardTitle title="Empty Component"/>
<DropDownMenu value={"Empty"} onChange={(event, index, value) => this.props.addPart(event, index, value, this.props.rowIndex, columnIndex)}>
<MenuItem value={"Empty"} primaryText="Empty" />
<MenuItem value={"Text"} primaryText="Textbox" />
<MenuItem value={"Image"} primaryText="Image" />
</DropDownMenu>
</Card>
</div>
</MuiThemeProvider>
)
} else if(column.type === 'Text') {
return (
<MuiThemeProvider key={columnIndex}>
<div className="textColumn">
<Card>
<DragHandle />
<CardTitle title="Textbox"/>
<DropDownMenu value={"Text"} onChange={(event, index, value) => this.props.addPart(event, index, value, this.props.rowIndex, columnIndex)}>
<MenuItem value={"Empty"} primaryText="Empty" />
<MenuItem value={"Text"} primaryText="Textbox" />
<MenuItem value={"Image"} primaryText="Image" />
</DropDownMenu>
<Text
value={this.props.row[columnIndex].value}
onChange={this.props.onChange}
columnIndex={columnIndex}
rowIndex={this.props.rowIndex} />
</Card>
</div>
</MuiThemeProvider>
)
} else if(column.type === 'Image') {
return (
<MuiThemeProvider key={columnIndex}>
<div className="textColumn">
<Card>
<DragHandle />
<CardTitle title="Image"/>
<DropDownMenu value={"Image"} onChange={(event, index, value) => this.props.addPart(event, index, value, this.props.rowIndex, columnIndex)}>
<MenuItem value={"Empty"} primaryText="Empty" />
<MenuItem value={"Text"} primaryText="Textbox" />
<MenuItem value={"Image"} primaryText="Image" />
</DropDownMenu>
<Image
columnIndex={columnIndex}
rowIndex={this.props.rowIndex} />
</Card>
</div>
</MuiThemeProvider>
)
}
})
return (
<div className="row">
{row}
</div>
)
}
return <p>No components</p>;
}
}
export default Row;
Lastly, this is what Text.js looks like
import React, { Component } from 'react';
import ReactQuill from 'react-quill';
class Text extends Component {
constructor(props) {
super(props);
}
render() {
return (
<ReactQuill value={this.props.value}
onChange={(text) => this.props.onChange(text, this.props.rowIndex, this.props.columnIndex)} />
)
}
}
export default Text;
So, I keep having to pass ridiculous parameters to onChange functions and other functions in order to ensure that the state is maintained while sorting and editing. So, how should I be handling this? I don't want Letter.js (which is basically App.js) to handle all of my data handling. I want each component to handle it's own. I want Text.js to handle the onChange effects of its text. But I just can't see a way around passing everything down as props.

Categories

Resources