I tried to create a button which gives me a popup window on click. The popup window contains a form which should let me type in any new entry. On submit, the entry should be passed to the main component.
I have two components. The main component is the 'App' component and the other component is the 'Popup' component.
Here is my code:
App.js
import React, { Component } from "react";
import Popup from "./Popup.js";
import "./styles.css";
class App extends Component {
showPopup = false;
createEntry = () => {
this.showPopup = true;
this.setState({ showPopup: this.showPopup });
};
handleSubmit = (value) => {
console.log("New Entry: " + value);
this.showPopup = false;
this.setState({ showPopup: this.showPopup });
};
render() {
return (
<React.Fragment>
<button onClick={this.createEntry}> + </button>
{this.showPopup ? <Popup handleSubmit={this.handleSubmit} /> : null}
</React.Fragment>
);
}
}
export default App;
Popup.js
import React, { Component } from "react";
import "./styles.css";
class Popup extends Component {
constructor(props) {
super(props);
this.state = {
value: ""
};
// I want to pass the submitted value to the App Component
this.handleSubmit = this.props.handleSubmit.bind(this, this.state.value);
this.handleChange = this.handleChange.bind(this);
}
handleChange = (event) => {
this.setState({ value: event.target.value });
};
render() {
return (
<React.Fragment>
<div className="popup">
<div className="popup_inner">
<div> Create New Entry </div>
<form onSubmit={this.handleSubmit}>
<label>
<input
type="text"
name="name"
value={this.state.value}
onChange={this.handleChange}
/>
</label>
<input type="submit" value="Submit" />
</form>
</div>
</div>
</React.Fragment>
);
}
}
export default Popup;
styles.css
.App {
font-family: sans-serif;
text-align: center;
}
.popup {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
background-color: rgba(0, 0, 0, 0.5);
}
.popup_inner {
position: absolute;
left: 25%;
right: 25%;
top: 25%;
bottom: 25%;
margin: auto;
background: white;
}
I tried to pass the 'value' to the 'handleSubmit' method by using handleSubmit as a prop method but that doesn't work.
What is an appropriate way to pass the value to the App component?
I'm still new to React, so please bear with me.
Thanks in advance.
The answer is in your question. You're passing it as a prop method and so you'll have to access it from the props.
In your Popup.js you can call the method passed from your parent as
onSubmit = {this.props.handleSubmit}
I have created a CodeSandBox to demonstrate the flow of data from parent to child components and vice versa
Related
At ReactJs I passed a change event to the child component, but I can't change the parent's state to show this value that came from the child.
I give a setState there at the parent, with the correct digit that comes from it, however the state does not change. Any help?
This father component:
import React from 'react';
import SnippetInput from './SnippetInput';
import BlockedInput from './BlockedInput';
export default class QuantityBlockedValue extends React.Component{
constructor(props){
super(props);
this.state = {
valorinput: 1,
valorbloqueado: 1
}
this.handleChangeSnippet = this.handleChangeSnippet.bind(this); //Event to passing to children
}
componentDidMount(){
let precoitem = (this.props.precoitem) ? this.props.precoitem : 1;
this.setState({valorbloqueado: this.state.valorinput * precoitem});
}
//Passing event change to children and execute here
handleChangeSnippet(event){
let digito = event.target.value;
let digitoInt = parseInt(digito);
if(digitoInt > 0){
//digitoInt return correc number from children, but valorinput state dont update! why??
this.setState({valorinput: digitoInt});
}
}
render(){
return(
<div>
<div className="center">
<h4>Quantity</h4>
<SnippetInput valorinput={this.state.valorinput} handleChange={this.handleChangeSnippet} />
<h4>Value</h4>
<BlockedInput valorbloqueado={this.state.valorbloqueado}/>
</div>
</div>
);
}
}
The children component:
import React from "react";
export default class SnippetInput extends React.Component{
constructor(props){
super(props);
this.state = {
valorinput : (this.props.valorinput) ? this.props.valorinput : 1
}
// this.handleChange = this.handleChange.bind(this);
this.handleAumentar = this.handleAumentar.bind(this);
this.handleDiminuir = this.handleDiminuir.bind(this);
}
handleAumentar(){
let digitoAumentado = this.state.valorinput + 1;
this.setState({valorinput: digitoAumentado});
}
handleDiminuir(){
let digito = this.state.valorinput;
if(digito > 1){
let digitoDiminuido = this.state.valorinput - 1;
this.setState({valorinput: digitoDiminuido});
}
}
render(){
let stylecorbotaodiminuir = "#F44336";
let stylecorbotaoaumentar = "#009688";
if(this.props.corBotaoDiminuir){
stylecorbotaodiminuir = this.props.corBotaoDiminuir;
}
if(this.props.corBotaoAumentar){
stylecorbotaoaumentar = this.props.corBotaoAumentar;
}
const stylebotaodiminuir = {
display: "inline-block",
width: "50px",
height: "50px",
backgroundColor: stylecorbotaodiminuir,
textAlign: "center"
};
const stylebotaoaumentar = {
display: "inline-block",
width: "50px",
height: "50px",
backgroundColor: stylecorbotaoaumentar,
textAlign: "center"
};
return (
<div>
<div>
<div id="diminuir" className="noTextSelect" style={stylebotaodiminuir} onClick={this.handleDiminuir}>
<span style={{fontSize: "30px", padding: "10px"}}>-</span>
</div>
<input style={{"width":"150px","textAlign": "center"}} type="text" value={this.state.valorinput} onChange={this.props.handleChange}/>
<div id="aumentar" className="noTextSelect" style={stylebotaoaumentar} onClick={this.handleAumentar}>
<span style={{fontSize: "30px", padding: "10px"}}>+</span>
</div>
</div>
</div>
);
}
}
I'm trying to programmatically trigger a onCancel event on Inline edit view component of Atlaskit, But I couldn't find any API docs where I can trigger on cancel event on this inline component.
import React from 'react';
import styled from 'styled-components';
import Textfield from '#atlaskit/textfield';
import { gridSize, fontSize } from '#atlaskit/theme';
import InlineEdit from '#atlaskit/inline-edit';
const ReadViewContainer = styled.div`
display: flex;
font-size: ${fontSize()}px;
line-height: ${(gridSize() * 2.5) / fontSize()};
max-width: 100%;
min-height: ${(gridSize() * 2.5) / fontSize()}em;
padding: ${gridSize()}px ${gridSize() - 2}px;
word-break: break-word;
`;
interface State {
editValue: string;
}
export default class InlineEditExample extends React.Component<void, State> {
state = {
editValue: 'Field value',
};
render() {
return (
<div
style={{
padding: `${gridSize()}px ${gridSize()}px ${gridSize() * 6}px`,
}}
>
<InlineEdit
defaultValue={this.state.editValue}
label="Inline edit"
editView={fieldProps => <Textfield {...fieldProps} autoFocus />}
readView={() => (
<ReadViewContainer>
{this.state.editValue || 'Click to enter value'}
</ReadViewContainer>
)}
onConfirm={value => this.setState({ editValue: value })}
/>
</div>
);
}
}
In my opinion the best way to do this is to use the InlineEditUncontrolled component and make it a controlled component using the following props: onConfirm, onCancel, isEditing. After that you can change internal isEditing state to false.
I have a search form with a lot of search components and a List container component which contains Item component to display the search results. When I click a selected Item, it pops up a Detail component. Right now, everything works fine except when clicking Close button inside the Detail component, the form gets reset and list of items also disappears. The Close button should just close the Detail component so I can select a different item in the list to view. What is the problem in my code? Thanks.
App.js
class App extends Component {
state={ showPopup: false,
selectedItem:'',
Items:[]};
togglePopup=()=> {
this.setState({
showPopup: !this.state.showPopup
});
}
onItemseSelect=(item)=>{
this.setState({selectedItem:item});
};
render(){
const Items=['aa','bb','cc'];
return(
<List
Items={this.state.Items}
onItemSelect={this.onItemSelect}
onClick={this.togglePopup}
/>
{this.state.showPopup ?
<Detail
item={this.state.selectedItem}
closePopup={this.togglePopup.bind(this)}
/>
: null
}
);
}
}
List.js
import React from 'react';
import Item from './Item';
const List=({Items,onItemSelect})=>{
const renderedList= Items.map(item=>{
return (
<Item key={item.ID} item={item} onItemSelect={onItemSelect} />
);
})
return <div>
{renderedList}</div>
}
export default List;
Item.js
import React from 'react';
const Item=({item, onItemSelect})=>{
return <div onClick={()=>onItemSelect(item)} >
<div class="content">
<div class="header">
{/*display contents*/}
View More
</div>
</div>
};
export default Item;
Detail.js
import React from 'react';
const Detail=({item,closePopup})=>{
if (!item){
return <div>loading</div>
}
return (
<div className='popup'>
<div className='popup_inner'>
<p>
{/*contents here*/}
</p>
<button onClick={()=>closePopup}>close me</button>
</div>
</div>);
};
export default Detail;
css code:
.popup {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
background-color: rgba(0,0,0, 0.5);
}
.popup_inner {
position: absolute;
left: 25%;
right: 25%;
top: 25%;
bottom: 25%;
margin: auto;
background: white;
}
No error message. The form resets to the original state.
I think the problem is here only, I doubt how your list items are rendered first time only.
Items:[]
render(){
const Items=['aa','bb','cc']; //static values which are not in use
return(
<List
Items={this.state.Items} //You are using state which is blank
onItemSelect={this.onItemSelect}
onClick={this.togglePopup}
/>
...
)
}
Complete Running code is like this.
In this official example of react-dropzone, a full screen drop zone is achieved by wrapping the whole app inside the <Dropzone /> component. I am creating a multi route app and feel that wrapping everything inside the <Dropzone /> component is not a very clean solution.
Is there a way to create a full screen/page drop zone in React without placing the <Dropzone /> component on the root level?
Create a route to a Dropzone form and adjust the height and size of the field by utilizing CSS.
Working example: https://codesandbox.io/s/l77212orwz (this example uses Redux Form, but you don't have to)
container/UploadForm.js
import React, { Component } from "react";
import { reduxForm } from "redux-form";
import ShowForm from "../components/showForm";
class UploadImageForm extends Component {
state = { imageFile: [] };
handleFormSubmit = formProps => {
const fd = new FormData();
fd.append("imageFile", formProps.imageToUpload[0]);
// append any additional Redux form fields
// create an AJAX request here with the created formData
};
handleOnDrop = newImageFile => this.setState({ imageFile: newImageFile });
resetForm = () => {
this.setState({ imageFile: [] });
this.props.reset();
};
render = () => (
<div style={{ padding: 10 }}>
<ShowForm
handleOnDrop={this.handleOnDrop}
resetForm={this.resetForm}
handleFormSubmit={this.handleFormSubmit}
{...this.props}
{...this.state}
/>
</div>
);
}
export default reduxForm({ form: "UploadImageForm" })(UploadImageForm);
components/showForm.js
import isEmpty from "lodash/isEmpty";
import React from "react";
import { Form, Field } from "redux-form";
import DropZoneField from "./dropzoneField";
const imageIsRequired = value => (isEmpty(value) ? "Required" : undefined);
export default ({
handleFormSubmit,
handleOnDrop,
handleSubmit,
imageFile,
pristine,
resetForm,
submitting
}) => (
<Form onSubmit={handleSubmit(handleFormSubmit)}>
<Field
name="imageToUpload"
component={DropZoneField}
type="file"
imagefile={imageFile}
handleOnDrop={handleOnDrop}
validate={[imageIsRequired]}
/>
<button
type="submit"
className="uk-button uk-button-primary uk-button-large"
disabled={submitting}
>
Submit
</button>
<button
type="button"
className="uk-button uk-button-default uk-button-large"
disabled={pristine || submitting}
onClick={resetForm}
style={{ float: "right" }}
>
Clear
</button>
</Form>
);
components/dropzoneField.js
import React, { Fragment } from "react";
import DropZone from "react-dropzone";
import { MdCloudUpload } from "react-icons/md";
import RenderImagePreview from "./renderImagePreview";
export default ({
handleOnDrop,
input,
imagefile,
meta: { error, touched }
}) => (
<div>
<DropZone
accept="image/jpeg, image/png, image/gif, image/bmp"
className="upload-container"
onDrop={handleOnDrop}
onChange={file => input.onChange(file)}
>
<div className="dropzone-container">
<div className="dropzone-area">
{imagefile && imagefile.length > 0 ? (
<RenderImagePreview imagefile={imagefile} />
) : (
<Fragment>
<MdCloudUpload style={{ fontSize: 100, marginBottom: 0 }} />
<p>Click or drag image file to this area to upload.</p>
</Fragment>
)}
</div>
</div>
</DropZone>
{touched && error && <div style={{ color: "red" }}>{error}</div>}
</div>
);
components/renderImagePreview.js
import map from "lodash/map";
import React from "react";
export default ({ imagefile }) =>
map(imagefile, ({ name, preview, size }) => (
<ul key={name}>
<li>
<img src={preview} alt={name} />
</li>
<li style={{ textAlign: "center" }} key="imageDetails">
{name} - {size} bytes
</li>
</ul>
));
styles.css
.dropzone-container {
text-align: center;
background-color: #efebeb;
height: 100%;
width: 100%;
}
.dropzone-area {
margin: 0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.upload-container {
height: 100vh;
width: 100%;
margin-bottom: 10px;
}
ul {
list-style-type: none;
}
p {
margin-top: 0;
}
Given the following code I am struggling to figure out how to set value of button back to original state, after it is clicked once ?
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
/**
* links : https://www.youtube.com/watch?v=GhbhD1HR5vk&t=297s
* https://reactjs.org/docs/handling-events.html
*
*
*
*/
class Input extends Component {
constructor(props) {
super(props);
this.state = {
tagged: false,
user: '',
tag: ''
}
this.handleUserChange = this.handleUserChange.bind(this);
}
handleClick(e) {
this.setState({tagged: true});
e.preventDefault();
console.log('The link was clicked.');
}
handleUserChange(e) {
console.log("e.target.value");
this.setState({user: e.target.value});
}
handleTagChange(e) {
console.log(e.target.value);
this.setState({tag: e.target.value});
}
render() {
return (
<div id="id" style={divStyle}>
<p> hello </p>
<input
style = {textStyle}
placeholder="user#email.com"
type="text"
onChange={ this.handleUserChange.bind(this) }
>
</input>
<input
style = {textStyle}
placeholder="tag"
type="text"
onChange={ (e) => this.handleTagChange(e) }
>
</input>
<button
onClick={(e) => this.handleClick(e)}
style={buttonStyle}>
{this.state.tagged ? 'Tagged' : 'Tag ' }
</button>
<p>
{this.state.tagged ? this.state.user + ' was tagged with ' + this.state.tag : ''}
{/* {this.setState({tagged: false})} */}
</p>
</div>
)
}
}
var divStyle = {
position: 'relative',
top:'50%',
left: '15%',
};
var textStyle = {
margin: '20px 20px 20px 20px',
height: '20px',
width: '200px',
};
var buttonStyle = {
margin: '20px 20px 20px 20px',
background: '#7FFFD4',
color: 'black',
height: '25px',
width: '250px'
};
export default Input;
set your state like this in your handClick method
this.setState((prevState)=> ({
tagged: !prevState.tagged
}));