react-modal - onChange on input is not updating state - javascript

I hope you will be able to help me with an answer to my question. I am using react-modal and inside the modal I have an input where users can write an email. When writing the email it should update the state but that is not happening.
What is happening right now is that the model re-renders every time I write a new letter and that results in the state only updating with the first letter I typed and then focus is lost.
I am using react hooks. I know that changes a bit.
My code looks like the following:
import React, { useState, useContext } from 'react';
import AppContext from '../../AppContext.jsx';
import GroupContext from './GroupContext.jsx';
import Section from '../../Elements/PageContent/Section.jsx';
import PageTitle from '../../Elements/PageContent/PageTitle.jsx';
import WhiteContainer from '../../Elements/PageContent/WhiteContainer.jsx';
import { Form, FormGroup, FormSection, FormSection_Split, Label, Input, Select, Submit } from '../../Elements/Forms/FormCollection.jsx';
import { MusicGenres } from '../../Elements/Forms/MusicGenres.jsx';
import { Years } from '../../Elements/Forms/Years.jsx';
import { H3 } from '../../Elements/Fonts/FontCollection.jsx';
import { Icon } from '../../Elements/Image/ImageUtil.jsx';
import ReactModal from "react-modal";
import { useModal } from "react-modal-hook";
export default function Groups(props) {
const AC = useContext(AppContext);
const GC = useContext(GroupContext);
const [groupName, setGroupName] = useState("");
const [groupDescription, setGroupDescription] = useState("");
const [memberEmail, setMemberEmail] = useState("");
const [groupMembers, setGroupMembers] = useState([]);
const [showModal, hideModal] = useModal(() => (
<ReactModal className="DialogPopup" isOpen ariaHideApp={false}>
<Form>
<FormGroup>
<FormSection>
<Label htmlFor="memberEmail" title="Email of your group member:" />
<Input type="email" name="memberEmail" value={memberEmail} onChange={(e) => setMemberEmail(e.target.value)} placeholder="#" />
</FormSection>
</FormGroup>
</Form>
<button onClick={(e) => hideModal()} className="Close" aria-label="Close popup"><Icon iconClass="fal fa-times" /></button>
</ReactModal>
), []);
async function addObjectToGroupMembersArray(e) {
e.preventDefault();
console.log("Adding member");
}
return (
<React.Fragment>
<PageTitle title="Add group" />
<Section>
<Form>
<FormGroup>
<FormSection>
<WhiteContainer>
<Label htmlFor="groupName" title="Group name:" />
<Input type="text" name="groupName" value={groupName} onChange={(e) => setGroupName(e.target.value)} maxLength="60" required />
<span className="CharactersLeft">Characters left: {60 - groupName.length}</span>
</WhiteContainer>
</FormSection>
<FormSection>
<WhiteContainer>
<Label htmlFor="groupDescription" title="Describe your group:" />
<textarea name="groupDescription" id="groupDescription" value={groupDescription} onChange={(e) => setGroupDescription(e.target.value)} maxLength="500"></textarea>
<span className="CharactersLeft">Characters left: {500 - groupDescription.length}</span>
</WhiteContainer>
</FormSection>
<FormSection>
<WhiteContainer>
<Label htmlFor="groupMembers" title="List the emails of your group members?" />
<a href="#" className="AddLink" aria-label="Add member" title="Click to add a member" onClick={(e) => { e.preventDefault(); showModal(); }}>
<Icon iconClass="fal fa-plus" />
</a>
</WhiteContainer>
</FormSection>
<FormSection className="FormSection--Submit">
<Submit text="Create group" />
</FormSection>
</FormGroup>
</Form>
</Section>
</React.Fragment>
);
}
Does anyone of you know why the modal is updating every time I type, resulting in not being able to write anything in the input. Should i use "ref" and if I should, how would I do that?
The onChange method I am using is always working, just not inside react-modal.

I finally figured it out. It's because modal is working a little like the useEffect hook. If i add memberEmail to the bottom of the modal state, then it is working.
const [memberEmail, setMemberEmail] = useState("");
const [showModal, hideModal] = useModal(() => (
<ReactModal className="DialogPopup" isOpen ariaHideApp={false}>
<Form>
<FormGroup>
<FormSection>
<Label htmlFor="memberEmail" title="Email of your group member:" />
<Input type="email" name="memberEmail" value={memberEmail} onChange={(e) => setMemberEmail(e.target.value)} placeholder="#" />
</FormSection>
</FormGroup>
</Form>
<button onClick={(e) => hideModal()} className="Close" aria-label="Close popup"><Icon iconClass="fal fa-times" /></button>
</ReactModal>
), [memberEmail]);

What about creating an external function that you would call in onChange?
something like:
const handleOnChange = (event) => {
setMemberEmail(event.target.value);
}
// then call it in your component
<Input type="email" name="memberEmail" value={memberEmail} onChange={handleOnChange} placeholder="#" />

Related

handling events in react

I need to make a login page, when I click the submit button this should be navigated to Dashboard page. The below is my code, what is the problem in it. When I give details in the login page and click on login, the details vanishes and not navigated to dashboard.
import React, { Component, useState } from "react";
import axios from 'axios';
import { setUserSession } from '../utils/common';
function Login(props) {
const username = useFormInput('');
const password = useFormInput('');
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
// handle button click of login form
const handleLogin = () => {
props.history.push('/dashboard');
}
return (
<form>
<h3>Sign In</h3>
<div className="form-group">
<label>Email address</label>
<input type="email" className="form-control" placeholder="Enter email" />
</div>
<div className="form-group">
<label>Password</label>
<input type="password" className="form-control" placeholder="Enter password" />
</div>
<div className="form-group">
<div className="custom-control custom-checkbox">
<input type="checkbox" className="custom-control-input" id="customCheck1" />
<label className="custom-control-label" htmlFor="customCheck1">Remember me</label>
</div>
</div>
{error && <><small style={{ color: 'red' }}>{error}</small><br /></>}<br />
<input type="button" className="btn btn-primary btn-block" value={loading ? 'Loading...' : 'Sign-in'} onClick={handleLogin} disabled={loading} /><br />
<p className="forgot-password text-right">
Forgot password?
</p>
</form>
);
}
const useFormInput = initialValue => {
const [value, setValue] = useState(initialValue);
const handleChange = e => {
setValue(e.target.value);
}
return {
value,
onChange: handleChange
}
}
export default Login;
Do you have a route defined for /dashboard. Everything worked me in code sandbox without react router setup. Psuedo code shown below
<Switch>
<Route path="/dashboard">
<DashboardComponent />
</Route>
</Switch>

Component is rendered before clicking on button in Reactjs

I am new to Reactjs . I am making a todo app using it . So in developing phase I want the Delete Button to console.log() the "hello" onClick. But whenever I submit a new todo task , even without click the delete button it console.log() the "hello" and if then I click Delete Button nothing happens on console.
I can't understand where's the problem . I surfed the internet but nothing worked.
May anyone tell where's the problem ?
Here's my code :
import './styles/App.css';
import { useState } from 'react';
import { Form, Button, ListGroup } from 'react-bootstrap';
import DropDown from './components/DropDowns';
import DeleteButton from './components/DeleteButton';
function App() {
const [todoList, setTodo] = useState([]);
const [Ttitle, setTitle] = useState('');
const [desc, setDesc] = useState('No Description');
return (
<div className="App d-flex flex-column">
<h1 className="mt-3">Your ToDo App</h1>
<div className="container-fluid mx-0 px-0">
<div className="Todo__Res mx-5">
<h2>Your ToDo List</h2>
<div className="List">
<ul className="Todo__List">
{todoList ? todoList.map((item, index) => <li key={index}>
<ListGroup>
<ListGroup.Item>{item.title}<DropDown desc={item.desc} /><DeleteButton index={index}/></ListGroup.Item>
</ListGroup>
</li>) : 0}
</ul>
</div>
</div>
<div className="Todo__Add mx-5">
<h2>Add Your ToDo</h2>
<Form>
<Form.Group controlId="exampleForm.ControlInput1">
<Form.Label>Title</Form.Label>
<Form.Control type="text" placeholder="Take Jack to School..." onChange={e => setTitle(e.target.value)} />
</Form.Group>
<Form.Group controlId="exampleForm.ControlTextarea1">
<Form.Label>Description</Form.Label>
<Form.Control as="textarea" rows={3} placeholder="Buy him a cake..." onChange={e => setDesc(e.target.value)} onDefault={desc} />
</Form.Group>
<Button variant="primary" type="submit" onClick={(e) => {
e.preventDefault();
const kk = {
title: Ttitle,
desc: desc
}
setTodo([...todoList, kk]);
}}>
Submit
</Button>
</Form>
</div>
</div>
</div>
);
}
export default App;
//Delete Button Component :
import {Button}from 'react-bootstrap'
export default function DeleteButton({index}){
return(
<>
<Button variant="outline-danger" onClick={console.log("hello")}>Delete</Button>
</>
);
}
Thanking You ,
Yours Truly
Rishabh Raghwendra
You are calling the function immediately on render. you should just pass a function to be executed on click
Here you go, this should fix your code issue,
<Button variant="outline-danger" onClick={() => console.log("hello")}>Delete</Button>

React.js submit button didn't work on Console Log?

when I click on the submit button on react js, Submit doesn't work, I don't know why?
I'm using ant.design Ui component in on backend Using Django python.
import React from "react";
import { Form, Input, Button } from "antd";
const FormItem = Form.Item;
class ExtrashiftForm extends React.Component {
handleFormSubmit = (event) => {
event.preventDefault();
const title = event.target.elements.title.value;
const manager = event.target.elements.manager.value;
const gender = event.target.elements.gender.value;
const Lable = event.target.elements.Lable.value;
const datetime = event.target.elements.datetime.value;
console.log(title, manager,gender,Lable,datetime);
};
render() {
return (
<div>
<Form onSubmit={this.handleFormSubmit}>
<FormItem name="title" label="Title">
<Input placeholder="title here" />
</FormItem>
<FormItem name="manager" label="Manager">
<Input placeholder="select Manager Name .. " />
</FormItem>
<FormItem name="gender" label="Gender">
<Input placeholder="select Gender Type .. " />
</FormItem>
<FormItem name="Lable" label="Lable">
<Input />
</FormItem>
<FormItem name="datetime" label="DateTime">
<Input />
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit">
Ok
</Button>
</FormItem>
</Form>
</div>
);
}
}
export default ExtrashiftForm;
this part of code included inside the layout page, and all text coming but when I check Console in chrome browser, didn't send any data to console.
please help me, thank you
Change onSubmit to onFinish.
onFinish cb will have values as object. That also need to update.
<Form onFinish={(values) => console.log(values)}>
or
<Form onFinish={({title, manager,gender,Lable,datetime}) => console.log({title, manager,gender,Lable,datetime})}>
Try this one
<Form onFinish={(values) => this.handleFormSubmit(values)}>
<FormItem label="Title">
<Input placeholder="title here" name="title" />
</FormItem>
</Form>
const handleFormSubmit = (values) => {
const title = values.title;
console.log(title);
};

How to display the information submitted in the html form on another page using react js?

I want to show all the details filled in the html form on another page using react js. I have created the html form which is the landing page. And after clicking on submit all the information should be displayed on another page.
My form.js page for creating the html form
import React, { component } from 'react';
var details = () => {
return(
<div>
<form>
Name: {" "}
<input type="text" placeholder="Enter name" /><br />
Contact No.: {" "}
<input type="number" placeholder="Enter contact number" />
<br />
<input type="submit" value="submit"/>
</form>
</div>
);
}
export default details;
My app.js page
import React from 'react';
import logo from './logo.svg';
import './App.css';
import Details from './form/form';
function App() {
return (
<div className="App">
<header className="App-header">
<Details />
</header>
</div>
);
}
export default App;
The data which you'll store in react state will be in browser memory and on refresh you'll lose that data.
In case, If you want functionality like the preview on form submit then you can store data in state and show/hide the preview on form submit.
So, Basically you can use state or some third party state management library to store the data. Here is a basic example of how you can achieve in the same details component.
import React, { useState } from 'react';
const Details = () => {
const [name, setName] = useState('');
const [number, setNumber] = useState(null);
const [showPreview, setShowPreview] = useState(false);
return(
<div>
{!showPreview && <form onSubmit={e => e.preventDefault()}>
Name: {" "}
<input type="text" placeholder="Enter name" onChange={e => setName(e.target.value)} /><br />
Contact No.: {" "}
<input type="number" placeholder="Enter contact number" onChange={e => setNumber(e.target.value)} />
<br />
<input type="button" value="submit" onClick={() => setShowPreview(!showPreview)}/>
</form>}
{showPreview && (<div>
<p>{name}</p>
<p>{number}</p>
</div>)}
</div>
);
}
export default Details;
Again, This answer is based on lots of assumptions. Maybe we need some more details in the question to have a precise answer.
In case if you want to display the same data on any other page then you can use Redux. Which can store the data in the redux store and you display the same data on another page.
First, on the app we want to create a function that can receive the data, then send it to the component as a prop:
import React from 'react';
import Details from './form';
function App() {
const getFormData = function (name, number) {
console.log('Name: ', name, 'Number: ', number)
}
return (
<div className="App">
<header className="App-header">
<Details sendFormData={getFormData} />
</header>
</div>
);
}
export default App
Then, inside the component you want to set each input to update their state as they change. When you click submit, you pass the state to the up to the app components getFormData function.
import React, { useState } from 'react';
const Details = (props) => {
const [userName, setName] = useState('');
const [userNumber, setNumber] = useState('');
const handleSubmit = () => {
props.sendFormData(userName, userNumber)
}
return (
<div>
Name: {" "}
<input type="text" placeholder="Enter name"
onChange={event => setName(event.target.value)} /><br />
Contact No.: {" "}
<input type="number" placeholder="Enter contact number"
onChange={event => setNumber(event.target.value)} />
<br />
<button onClick={() => handleSubmit()} >Submit</button>
</div>
);
}
export default Details;

Redux Form Field Arrays-initializing a field array with a specific length

I would like for my form component to start off with a field array with 3 empty fields. Can anyone explain how to initialize it this way?
I'm going off the example provided in the documentation here: https://redux-form.com/7.0.4/examples/fieldarrays/
Here, we can see that originally, we have no fields, and only when we click on the relevant button do we add them, by calling onClick={() => fields.push({})}.
I'd like to start off with three fields and allow the user to add more. Calling fields.push in ComponentDidMount doesn't work. How do I initialize the fields object with a specific length?
FieldArraysForm.js
import React from 'react'
import { Field, FieldArray, reduxForm } from 'redux-form'
import validate from './validate'
const renderField = ({ input, label, type, meta: { touched, error } }) =>
<div>
<label>
{label}
</label>
<div>
<input {...input} type={type} placeholder={label} />
{touched &&
error &&
<span>
{error}
</span>}
</div>
</div>
const renderHobbies = ({ fields, meta: { error } }) =>
<ul>
<li>
<button type="button" onClick={() => fields.push()}>
Add Hobby
</button>
</li>
{fields.map((hobby, index) =>
<li key={index}>
<button
type="button"
title="Remove Hobby"
onClick={() => fields.remove(index)}
/>
<Field
name={hobby}
type="text"
component={renderField}
label={`Hobby #${index + 1}`}
/>
</li>
)}
{error &&
<li className="error">
{error}
</li>}
</ul>
const renderMembers = ({ fields, meta: { error, submitFailed } }) =>
<ul>
<li>
<button type="button" onClick={() => fields.push({})}>
Add Member
</button>
{submitFailed &&
error &&
<span>
{error}
</span>}
</li>
{fields.map((member, index) =>
<li key={index}>
<button
type="button"
title="Remove Member"
onClick={() => fields.remove(index)}
/>
<h4>
Member #{index + 1}
</h4>
<Field
name={`${member}.firstName`}
type="text"
component={renderField}
label="First Name"
/>
<Field
name={`${member}.lastName`}
type="text"
component={renderField}
label="Last Name"
/>
<FieldArray name={`${member}.hobbies`} component={renderHobbies} />
</li>
)}
</ul>
const FieldArraysForm = props => {
const { handleSubmit, pristine, reset, submitting } = props
return (
<form onSubmit={handleSubmit}>
<Field
name="clubName"
type="text"
component={renderField}
label="Club Name"
/>
<FieldArray name="members" component={renderMembers} />
<div>
<button type="submit" disabled={submitting}>
Submit
</button>
<button type="button" disabled={pristine || submitting} onClick={reset}>
Clear Values
</button>
</div>
</form>
)
}
export default reduxForm({
form: 'fieldArrays', // a unique identifier for this form
validate
})(FieldArraysForm)
Thanks to the Redux Form team:
https://github.com/erikras/redux-form/issues/3640
Basically, the way it's done is to pass in an array of initial values to the form when you connect and export it, something like this:
export default reduxForm({
form: "foo",
initialValues: {
rockSingers: ['Axl Rose', 'Brian Johnson']
},
onSubmit: values => {
window.alert( "Submited: \n" + JSON.stringify( values, null, 2 ) );
}
})( MyForm );

Categories

Resources