Trying to make the onChange event of the following componenet to fire but it does not. When I type in the seach box nothing is printed on the console. No change is fired
const Search = () => {
let history = useHistory()
const [search, setSearch] = useState('')
const handleSubmit = (e) => {
e.preventDefault()
if (search) {
console.log("typing..")
history.push(`/?search=${search}`)
} else {
history.push(history.push(history.location.pathname))
}
}
return (
<Form.Group controlId='searchbox' onSubmit={handleSubmit}>
<Form.Control
className="auth-input"
type='text'
placeholder="Search..."
onChange={(e) => setSearch(e.target.value)}
>
</Form.Control>
<Button type='submit'>Submit</Button>
</Form.Group>
)
}
export default Search
const Home =()=>{
return (<div><Search /><div>)
}
export default Home
I still can't identify where the error is. How do I get it working?
I am assuming Form.Control is a custom control or a third-party control, hence you cannot convert it to a controlled input. You could try creating a ref and get the value from the ref in the onChange event handler. If the custom control is not a third party control, then you could add the onChange handler inside the Form.Control component and pass a function reference to the control.
Edit:
Here is your solution : https://codesandbox.io/s/vigorous-mclean-4jusl?file=/src/App.js
In case you see an error in the sandbox, refresh the page. There seems to be some error with codesandbox.
Explanation:
Create a ref to access the input using useRef:
const controlref = useRef();
Pass the ref to the control:
<Form.Control
onChange={handleChange}
**ref={controlref}**
type="text"
placeholder="search..."
/>
Get the value in onChange using the ref:
const handleChange = (e) => {
console.log(controlref.current.value);
setSearch(controlref.current.value);
};
Firstly, html "input" is a self closing element.
Secondly, You have missed the "value" inside the Input component.
Your code:
<Form.Control
className="auth-input"
type='text'
placeholder="Search..."
onChange={(e) => setSearch(e.target.value)}
></Form.Control>
Solution:
<Form.Control
className="auth-input"
type='text'
placeholder="Search..."
onChange={(e) => setSearch(e.target.value)}
value={search}
/>
Try using event onInput instead:
<Form.Control
className="auth-input"
type='text'
placeholder="Search..."
onInput={(e) => setSearch(e.target.value)}
/>
I can't believe I made this silly mistake. The issue is due to the fact that I omitted the tag and placed the submit button within the <Form.Group> which doesn't have the property to handle onSubmit event. So I changed this
return (
<Form.Group controlId='searchbox' onSubmit={handleSubmit}>
<Form.Control
className="auth-input"
type='text'
placeholder="Search..."
onChange={(e) => setSearch(e.target.value)}
>
</Form.Control>
<Button type='submit'>Submit</Button>
</Form.Group>
)
It was modified to this:
return (
<Form onSubmit={handleSubmit} >
<Form.Group controlId='searchbox' >
<Form.Control
className="auth-input"
type='text'
placeholder="Search..."
onChange={(e) => setSearch(e.target.value)}
>
</Form.Control>
<Button type='submit'>Submit</Button>
</Form.Group>
</Form>
)
Related
Problem
I'm working on project using reactjs and graphql with apollo client. I'm trying to get user by id and it works, the value shows in the form modal.
But, I can't delete or add the text or content inside form input.
I'm using onChange handler but it doesn't work. here's the code
import React, { useEffect, useState } from "react";
import { useMutation, useQuery } from "#apollo/client";
import { Button, Modal, Form } from "react-bootstrap";
import { GET_USER_BY_ID } from "../../../gql/query";
const ModalEdit = (props) => {
// state for check input component
const [isChecked, setIsChecked] = useState('ACTIVE');
const [value, setValue] = useState({
full_name: "",
email: "",
phone: "",
address: "",
password: "",
group_id: "",
});
useEffect(() => {
if (props.show) {
document.body.classList.add("modal-open");
}
return () => {
if (document.body.classList.contains("modal-open")) {
document.body.classList.remove("modal-open");
}
};
}, [props.show]);
const { data, loading, error } = useQuery(GET_USER_BY_ID, {
variables: { username: props.username },
});
const dataUser = data?.getUserByID;
if (loading) return <p>Loading...</p>;
if (error) return <p>Error!</p>;
const onChange = (event) => {
setValue({
...value,
[event.target.name]: event.target.value
})
}
return (
<Modal show={props.show}>
<Modal.Header>
<Modal.Title> <span>FORMULIR AKUN PENGGUNA</span> </Modal.Title>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group className="mb-3">
<Form.Label>Role Akun</Form.Label>
<Form.Select aria-label="pilih user role">
<option>{dataUser.group_id}</option>
<option>Admin RJ</option>
</Form.Select>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Nama Lengkap</Form.Label>
<Form.Control name="full_name" value={dataUser.full_name} onChange= {onChange} />
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Email</Form.Label>
<Form.Control type="email" name="email" value={dataUser.email} onChange={ onChange }/>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Phone</Form.Label>
<Form.Control type="text" name="phone" value={dataUser.phone} onChange={ onChange } />
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Address</Form.Label>
<Form.Control type="text" name="address" value={dataUser.address} onChange={ onChange } />
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Password</Form.Label>
<Form.Control type="password" name="password" value={dataUser.password} onChange={ onChange } />
</Form.Group>
<Form.Label>Aktifkan Akun</Form.Label>
{dataUser.status === 'ACTIVE' ? (
<Form.Check
type="switch"
checked={isChecked}
onChange={(event) => setIsChecked(event.target.checked)}
id="custom-switch"
label="Aktifkan Akun"
/> ) : (
<Form.Check
type="switch"
id="custom-switch"
checked={isChecked}
onChange={(event) => setIsChecked(event.target.checked)}
label="Aktifkan Akun"
/>
)}
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant="primary" type="submit" >Submit</Button>
<Button variant="secondary" onClick={props.onClose}>
Close
</Button>
</Modal.Footer>
</Modal>
);
};
export default ModalEdit;
Question
How can i'm edit the form input?
Any help will be apprieciated, thank you
The value prop of your inputs are causing this issue. Instead of binding the value directly to dataUser.address and such, you should set them to value.address and so on.
As for showing the user's data, you should map the values when creating the state.
Your state should be as follows:
const [value, setValue] = useState({
full_name: dataUser.full_name,
email: dataUser.email,
phone: dataUser.phone
address: dataUser.address,
password: dataUser.password,
group_id: dataUser.group_id,
});
And your input should be as follows:
<Form.Control name="full_name" value={value.full_name} onChange= {onChange} />
Have separete handlers where handleSubmit is to submit to server while handleAdd is for keeping some values in UI component states.
const handleSubmit = (event) => {
const isValid = event.currentTarget.checkValidity();
if (!isValid) {
setValidated(true);
} else {
//Submitting to server
}
}
const handleAdd = (event) => {
const isValid = isInnerValid();
if (!isValid) {
setValidated(true); //This enables validation for outer fields as well but I am expecting not to.
} else {
//Saving in component states.
}
}
<Fragment>
<Form noValidate validated={validated} onSubmit={handleSubmit}>
//Main form
<Form.Group>
<Form.Label>
Outer field:
</Form.Label>
<InputGroup hasValidation>
<Form.Control required type="text" ... />
<Form.Control.Feedback type="invalid">
This field is required.
</Form.Control.Feedback>
</InputGroup>
</Form.Group>
//Sub-section of form
<Form.Group>
<Form.Label>
Inner field:
</Form.Label>
<InputGroup hasValidation>
<Form.Control required type="text" ... />
<Form.Control.Feedback type="invalid">
This field is required.
</Form.Control.Feedback>
</InputGroup>
//On click of of Add button dont want to validate Outer field.
<Button onClick={handleAdd}>
Add
</Button>
</Form.Group>
//Submit button for whole form.
<Button type="submit">
Submit
</Button>
</Form>
</Fragment>
On click of Add but I want to validate only the Inner field not Outer Field
The validation on form level enables validation on all fields, how to separate it out?
Okay so I've attempted this 2 different ways and both give me a value of "undefined" instead of the answer that the user puts into the form, I'm using material UI forms if that helps.
The 2 ways I did is:
1. I have a button at the end that submits, which is the preferred way I want to do it and then display the data after.
2. I'm trying it as the user types so using onChange and it'll update on the UI as the user types.
Neither ways have been working because even when I submit or type I get console.log saying "undefined" each time, so I don't even know if I'm pulling results.
My end goal is to get the form data into variables and then upload those into the backend (to use on other pages of the app) and from the backend pull the information to display on this page so the user can see their information.
Any help is appreciated, thank you!
class AccountPage extends React.Component {
constructor () {
super()
this.state = {
email: '',
socMed1: ''
}
}
handleSubmit(event){
alert("test")
}
handleChange (event) {
this.setState( {[event.target.name]: event.target.value });
console.log(event.name)
}
render() {
return (
<div>
<h1>
{this.email}
</h1>
<form action="/" method="POST" onSubmit={(e) => { e.preventDefault(); this.handleSubmit(); } }>
<TextField
id="standard-name"
style={{ margin: 15 }}
label="Name"
margin="normal"
name="email"
value={this.state.email}
onChange={event => this.handleChange(event)}
/>
<TextField
id="standard-name"
style={{ margin: 15 }}
label="Location"
margin="normal"
/>
<TextField
id="standard-select-socialmedia"
select
style={{ margin: 15 }}
label="Select"
SelectProps={{
MenuProps: {},
}}
helperText="Please select your main social media"
margin="normal"
name = "socMed1"
value={this.state.socMed1}
onChange={event => this.handleChange(event)}
>
Assuming you have submit button at the bottom,
something like (you can use material ui one)
<button onSubmit={(event) => this.handleSubmit(event)} />
and try adding this to your alert
alert(`email: ${this.state.email}, socMed1: ${this.state.socMed1}`)
then you will see what user typed in field
Hope it helps!
a functional component with form. checkout Just do some research this is just HTML functionality. if you want to use class component you can go ahead but just use "this.handleSubmit in onSubmit form would work
import React from "react";
import TextField from "#material-ui/core/TextField";
import Button from "#material-ui/core/Button";
const Demo = () => {
const handleSubmit = event => {
const formData = new FormData(event.target);
//does not resets the form
event.preventDefault();
// accessing each values
for (var [key, value] of formData.entries()) {
console.log(key, value);
}
// posting you values to api
fetch("/api/form-submit-url", {
method: "POST",
body: formData
});
};
return (
<React.Fragment>
<form onSubmit={handleSubmit}>
<div style={{ display: "flex", flexDirection: "column" }}>
// names are important because this will be treated as a key value pair in handle submit.
<TextField id="standard-basic" name="user" label="user" />
<TextField id="standard-basic" name="email" label="email" />
<TextField id="standard-basic" name="password" label="password" />
<Button type="submit" variant="contained">
Submit
</Button>
</div>
</form>
</React.Fragment>
);
};
I am trying to add some validation to my React + Bootstrap project but I am not able to achieve this. According to Bootstrap Form validation documentation I have to provide a Form.Control.Feedback component to the Form Group component.
But is not showing the errors but check marks like everything is fine. I created this Code Sandbox yo demostrate what I need to achieve and what is showing me:
And just in case, this is the code if you don't need the sandbox to see the error:
import React, { useState } from "react";
import "./styles.css";
import { Container, Form, Button } from "react-bootstrap";
import validator from "validator";
import empty from "is-empty";
export default function App() {
const [validated, setValidated] = useState(false);
const [errors, setErrors] = useState({});
const [phone, setPhone] = useState("");
const [email, setEmail] = useState("");
const handleSubmit = async e => {
e.preventDefault();
const errors = {};
// validation
if (!validator.isMobilePhone(phone, ["es-UY"])) {
errors.phone = "Invalid phone number";
}
if (!validator.isEmail(email)) {
errors.email = "Invalid email address";
}
if (!empty(errors)) {
setErrors(errors);
}
setValidated(true);
};
return (
<Container>
<Form validated={validated} onSubmit={handleSubmit}>
<h1>Test form</h1>
<Form.Group controlId="phone">
<Form.Label>Phone number</Form.Label>
<Form.Control
type="tel"
value={phone}
onChange={e => setPhone(e.target.value)}
/>
<Form.Control.Feedback type="invalid">Error</Form.Control.Feedback>
{errors.phone && (
<Form.Control.Feedback type="invalid">
{errors.phone}
</Form.Control.Feedback>
)}
</Form.Group>
<Form.Group controlId="email">
<Form.Label>Email address</Form.Label>
<Form.Control
type="email"
value={email}
onChange={e => setEmail(e.target.value)}
feedback="Error"
/>
{errors.email && (
<Form.Control.Feedback type="invalid">
{errors.email}
</Form.Control.Feedback>
)}
</Form.Group>
<Form.Group controld="submit">
<Button type="submit" variant="primary">
Submit
</Button>
<Button
type="reset"
variant="info"
style={{ marginLeft: 10 }}
onClick={() => {
setErrors({});
setValidated(false);
}}
>
Reset
</Button>
</Form.Group>
</Form>
</Container>
);
}
So, what am I doing wrong?
Make sure you've set setValidated as false for the errors
const handleSubmit = async e => {
e.preventDefault();
const allErrors = {}; // <--- changed this as well
// validation
if (!validator.isMobilePhone(phone, ["es-UY"])) {
allErrors.phone = "Invalid phone number";
}
if (!validator.isEmail(email)) {
allErrors.email = "Invalid email address";
}
if (!empty(allErrors)) {
setErrors(allErrors);
setValidated(false);
}
else {
setValidated(true);
}
};
In your field add isInvalid as props:
<Form.Control
type="tel"
value={phone}
isInvalid={!!errors.phone} <------
onChange={e => setPhone(e.target.value)}
/>
<Form.Control
type="text"
value={email}
isInvalid={!!errors.email} <-----
onChange={e => setEmail(e.target.value)}
feedback="Error"
/>
I'm new to react thus the question.
This is my CustomModal,
import React from 'react';
import {useState} from "react";
import {Button, Modal} from "react-bootstrap";
const CustomModal = (props) =>{
const [show, setShow] = useState(true);
const handleClose = () => setShow(false);
return (
<div>
<Modal show={show} animation={false}>
<Modal.Header closeButton>
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>{props.message}</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
</Modal.Footer>
</Modal>
</div>
)
};
export default CustomModal;
I want to render it inside a class component when user submits a registration form.
class Register extends React.Component {
state = {
email : '',
username: '',
password: '',
second_password: ''
};
handleSubmit = async (event) =>{
event.preventDefault();
const emailValidated = await this.validateEmail(this.state.email);
const usernameValidated = this.validateUsername(this.state.username);
const passwordValidated = this.validatePassword(this.state.password, this.state.second_password);
let registrationComplete = false;
if(emailValidated === true && usernameValidated === true && passwordValidated === true){
registrationComplete = await this.register(this.state.email, this.state.username, this.state.password);
console.log(registrationComplete);
this.showModal("Hello World!"); //This is the function begin called to show the modal.
}
};
validateUsername = (username) =>{
return true;
};
validatePassword = (password, second) =>{
return true;
};
validateEmail = async (email) =>{
return true;
};
//This is the function that should display the modal
showModal = (message) =>{
return (<CustomModal message={message}/>);
};
register = async (email, username, password) =>{
return true;
};
render() {
return (
<div className="register">
<h1>Register</h1>
<Form onSubmit={this.handleSubmit}>
<Form.Group controlId="formBasicEmail">
<Form.Label>Email address</Form.Label>
<Form.Control type="email"
placeholder="Enter email"
value={this.state.email}
onChange={event => this.setState({email: event.target.value})}/>
<Form.Text className="text-muted">
Please make sure you've access to this mail. You'll receive an activation code here.
</Form.Text>
</Form.Group>
<Form.Group controlId="formPlainText">
<Form.Label className="form-label">Username</Form.Label>
<Form.Control type="text"
placeholder="Username"
value={this.state.username}
onChange={event => this.setState({username: event.target.value})}/>
<Form.Text className="text-muted">
Please make it atleast 8 characters long.
</Form.Text>
</Form.Group>
<Form.Group controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control type="password"
placeholder="Password"
value={this.state.password}
onChange={event => this.setState({password: event.target.value})}/>
<Form.Text className="text-muted">
Please make sure it's atleast 8 characters long and uses a mix of letters and numbers.
</Form.Text>
</Form.Group>
<Form.Group controlId="formBasicPassword">
<Form.Label>Retype Password</Form.Label>
<Form.Control type="password"
placeholder="Password"
value={this.state.second_password}
onChange={event => this.setState({second_password: event.target.value})}/>
</Form.Group>
<Button variant="primary" type="submit">
Register
</Button>
</Form>
</div>
);
}
}
export default Register;
All the values are correct and the console log shows true but the Modal doesn't display. Can someone help me with this?
There are some issues on your code
The customModal has to be part of the render of the Register component
There should be a state to track the status of the modal from the Register component
Also the register has to be notified when the Modal closes
I have modified your code and working. You can find it live here
I prefer attack this problem creating portals here documentation.
you might to have issues with z-index in the future.
Basically, you create an element outside the DOM hierarchy.
Now, your issue is that, you must render modal inside render method and control it, with boolean state "showModal".
I prepare for you an example:
example in my GitHub account
git clone ...
npm install
npm run start
preview: