Why is preventDefault() not working in ReactJS properly? - reactjs

I have a "Join" button:
const sendMessage = (e) => {
if (message) {
socket.emit('send', message, ()=>{setMessage('')});
}
}
return (
<div>
<input value={message}
onChange={(e)=>{
setMessage(e.target.value);}}
onKeyPress={(e)=>{return e.key==='Enter' ? sendMessage(e) : console.log('no good');}}
/>
</div>
)
After filling out the input field and pressing Enter, my socket-io id changes due to page refreshing. To prevent refresh, I used e.preventDefault() in sendMessage function, but despite it, the page refreshes anyway and the socket-io id changes. How to prevent page-refresh?

Your input will only cause a refresh if it's within a form which your example is not. If you need to prevent a refresh from the form you can do it within onSubmit like the following example.
import React, { useState } from "react";
export default function App() {
const [message, setMessage] = useState("");
function sendMessage(e) {
console.log(e);
}
function handleSubmit(e) {
e.preventDefault();
}
return (
<div className="App">
<form onSubmit={handleSubmit}>
<input
value={message}
onChange={(e) => {
setMessage(e.target.value);
}}
onKeyPress={(e) => {
return e.key === "Enter" ? sendMessage(e) : console.log("no good");
}}
/>
</form>
</div>
);
}

Related

Input component > feeds Forms component - how to handle submit?

I am missing how to bring the input value out of the child component.
I have an Input component that I want to re-use, there I can see what happens onChange, and I see every change on the input field.
Then on the parent component, Form, where I use <Input />, I have the rest of the form with the Submit button. At this level, I want to handle onSubmit, but I cannot see/console the value of the input here. I can only see it from the child.
Any ideas about what I am doing wrong?
Input.js - here I can see the input value onChange
function Input(props) {
const { label, name, value } = props;
const handleChange = (event) => {
const updateForm = {...Form};
console.log("change:", updateForm)
updateForm[label] = event.target.value;
}
return (
<label>
{label}
<input name={name} value={value} onChange={handleChange}></input>
</label>
)
}
export { Input }
Forms.js - here I cannot get access to the input value and submit/handle it
function Form(props) {
const handleSubmit = (event) => {
event.preventDefault();
console.log(Input.value);
console.log(props.label.value)
alert(`form is: ${event.target.input}`);
}
return (
<>
<form onSubmit={handleSubmit}>
<Input label={props.label} />
<input type="submit" value="Submit"></input>
</form>
</>
)
}
I have that structure because I am defining what I want in my Form on the main HomePage component:
function Home() {
return (
<>
.......
<Section withForm label={["Name"]} {...homeObjFive}/>
<Section withForm label={"Phone"} {...homeObjOne}/>
.......
</>
)
}
This is the perfect case to use the useRef function from react.
In Form.js
import React, { useRef } from 'react'
create a reference constant and pass it as a prop into the input component. and change the input value that is handled in the onSubmit function to the reference
Also in Form.js (changes are made to the submit function)
function Form(props) {
const { inputValue } = useRef(); // added
const handleSubmit = (event) => {
event.preventDefault();
console.log(inputValue); // changed
console.log(props.label.value)
alert(`form is: ${event.target.input}`);
}
return (
<>
<form onSubmit={handleSubmit}>
{/* added the inputValue prop to the input component */}
<Input label={props.label} inputValue={inputValue} />
<input type="submit" value="Submit"></input>
</form>
</>
)
}
and now inside of the Input component set the input elements reference to the inputValue prop. you will no longer need a onChange function as reacts useRef function is updated automatically
In Input.js
function Input(props) {
return (
<label>
{props.label}
<input name={props.name} value={props.value} ref={props.inputValue}></input>
</label>
)
}
export { Input }
Suppose you have a form with two inputs, name and email (these are the id props of the inputs). You can extract the form values like this:
const handleSubmit = (event) =>
{
event.preventDefault()
const data = new FormData(event.currentTarget)
const name = data.get('name')
const email = data.get('email')
// do something with the data
}
You can read more about FormData here.

Hello everyone I would like to make a radio button and make it select by pressing Enter key in React

I Am failing to get the radio button selected when I press the Enter key
I tried this code here :
import { useState, useEffect } from 'react';
const HandleKeypress = () =\> {
const [itWorks, setItWorks] = useState(true)
useEffect(() => {
document.addEventListener('keypress', (e) => {
if (e.code === 'Enter') setItWorks(!itWorks)
e.preventDefault();
})
}, [])
return (
<div>
<p>{itWorks ? 'It works!' : 'It does not'}</p>
<button onClick={() => setItWorks(!itWorks)} >Press me</button>
<input type='radio' aria-selected onKeyPress={() => this.HandleKeypress } />
</div>
)
}
export default HandleKeypress;
You dont have to use onKeyPress() use onClick() instead.
You are using functional component, so, do
<input type='radio' aria-selected onClick={handleClick} />
You cant call the main component which you are working on.
So, the solution for this is
import { useState, useEffect } from 'react';
const HandleKeypress = () => {
const [itWorks, setItWorks] = useState(false)
function handleClick(){
SetItWorks(true)
}
return (
<div>
<p>{itWorks ? 'It works!' : 'It does not'}</p>
<button onClick={() =>
setItWorks(!itWorks)} >Press me</button>
<input type='radio' aria-selected onClick={handleClick} />
</div>
)
}
export default HandleKeypress;
This will work.

file upload using react-step-builder form with multiple pages

i am using react hook form to create a from with multiple pages
i am able to create it and it working with all filed except file-input-type how do i pass i file from another page and finaly pass it to api in the final page
i a have actualy 3 pages i have only added the 1st and final page (fist page has the file input filed and final page has the api to which it must be submitted)
form with file upload field
import { useForm } from "react-hook-form";
export default function Form(props) {
const {
register,
handleSubmit,
formState: { errors },
} = useForm();
<input style={styles.file} type="file" />
</div>
<input {...register("name", { required: true })}
name="husband"
value={props.getState("name")}
onChange={props.handleChange}
style={styles.input}
type="text"
placeholder="Name"
/>
<input onClick={handleSubmit(props.next)}
type="submit"
value="Next"
/>
form with submit button and api to which it must be uploaded
const {
register,
handleSubmit,
formState: { errors },
} = useForm();
const submitValue = (e) => {
// e.preventDefault();
props.state.patient = "true";
const data = props.state;
axios
.post("registration/", data)
.then(() => {
alert("updated data");
window.location = "/clogin";
})
.catch((error) => {
//var my_obj_str = JSON.stringify(error.response.data);
alert(JSON.stringify(error.response.data));
});
};
codesandbox
https://codesandbox.io/s/wizardly-worker-zicnr?file=/src/App.js
There are 2 options
Single form wraps all the steps
You can wrap the <Steps /> component with one form. Make the <Step />s components stateless that accepts onInputChange which will called upon input changes.
onInputChange call setValue to update the form's state.
When the form submitted, you have the file (among other inputs) so you can send it to the server.
import { useEffect } from "react";
import { Steps, StepsProvider, useSteps } from "react-step-builder";
import { useForm } from "react-hook-form";
export default function App() {
const { register, handleSubmit, setValue } = useForm();
useEffect(() => {
register("myFile");
}, [register]);
const onInputChange = (e) => {
setValue(e.target.name, e.target.files[0]);
};
const onSubmit = (data) => {
alert(`Your file name: ${data.myFile.name}, size: ${data.myFile.size}`);
};
return (
<StepsProvider>
<form onSubmit={handleSubmit(onSubmit)}>
<MySteps onInputChange={onInputChange} />
</form>
</StepsProvider>
);
}
const MySteps = ({ onInputChange }) => {
const { next, prev } = useSteps();
return (
<Steps>
<div>
<h1>Step 1</h1>
<input type="file" name="myFile" onChange={onInputChange} />
<button onClick={next}>Next</button>
</div>
<div>
<h1>Step 2</h1>
<button>Submit</button>
</div>
</Steps>
);
};
https://codesandbox.io/s/gifted-wozniak-of14l?file=/src/App.js
Multiple forms in each step
If you want need to have a form inside each step, you can pass the step's data up to the parent when upon step's form submission. Still the parent has the form state so it can handle when all the steps completed
import { useRef } from "react";
import { Steps, StepsProvider, useSteps } from "react-step-builder";
import { useForm } from "react-hook-form";
export default function App() {
const formState = useRef();
const onStepComplete = (data) => {
formState.current = {
...formState.current,
...data
};
};
const onComplete = (data) => {
onStepComplete(data);
const {
name,
myFile: [file]
} = formState.current;
alert(
`Your name: ${name} Your file name: ${file.name}, size: ${file.size}`
);
};
return (
<StepsProvider>
<MySteps onStepComplete={onStepComplete} onComplete={onComplete} />
</StepsProvider>
);
}
const MySteps = ({ onStepComplete, onComplete }) => {
return (
<Steps>
<Step1 onStepComplete={onStepComplete} />
<Step2 onComplete={onComplete} />
</Steps>
);
};
const Step1 = ({ onStepComplete }) => {
const { register, handleSubmit } = useForm();
const { next } = useSteps();
const onSubmit = (data) => {
onStepComplete(data);
next();
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<h1>Step 1</h1>
<input type="file" {...register("myFile")} />
<button>Next</button>
</form>
);
};
const Step2 = ({ onComplete }) => {
const { register, handleSubmit } = useForm();
const onSubmit = (data) => {
onComplete(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<h1>Step 2</h1>
<input type="text" {...register("name")} />
<button>Submit</button>
</form>
);
};
https://codesandbox.io/s/condescending-leaf-6gzoj?file=/src/App.js
Passing down the function and tracking changes at parent level is not a great idea. react-hook-form provides a form context option which allows you to do this independently. Such that errors, onChange are handled in each step separately. But when you need to submit the data you can get all of those in the parent component.
Refer to this documentation: https://react-hook-form.com/api/useformcontext/
Note: Many people make the mistake of placing the FormProvider inside the parent component. Remember that FormProvider should wrap the Parent component as well.

cannot clear form field with functional react hook in reactjs

The code below works fine by submit a post message. now i want to clear the message input form on form submission but cannot get it to work. I have tried the following 3 options but yet no luck.
1.)
function clearState() {
message('');
}
// pass the clear state function on form submission
clearState();
2.) Clear form by referencing the form id
document.getElementById('my_form').reset();
3.) using event target reset
event.target.reset();
here is the full code.
import React, { useState, useRef, useEffect } from "react";
export default function App(props) {
const [message, setMessage] = useState("");
const [messages, setMessages] = useState([]);
const currentDate = new Date();
useEffect(() => {
// fetch content axio or ajax
}, []);
function clearState() {
message('');
}
function handleChange(event) {
setMessage(event.target.value);
}
function handleSubmit(event) {;
event.preventDefault();
const newMessages = messages;
const data = { message: message, date: new Date() };
setMessages(newMessages.concat([data]));
//clear all form field based on form id
clearState();
//document.getElementById('my_form').reset();
//event.target.reset();
}
return (
<React.Fragment>
<div className="chat_container">
{messages.map((m, e) => (
<div key={e}>
<div className="chat_message">
chat: {m.message} ---{m.date.toLocaleTimeString()}
</div>
</div>
))}
</div>
<div className="myFooter">
<form id"my_form" onSubmit={handleSubmit}>
<label>
Name:
<input type="text" value={message} onChange={handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
</div>
</React.Fragment>
);
}

How to submit a form using Enter key in react.js?

Here is my form and the onClick method. I would like to execute this method when the Enter button of keyboard is pressed. How ?
N.B: No jquery is appreciated.
comment: function (e) {
e.preventDefault();
this.props.comment({
comment: this.refs.text.getDOMNode().value,
userPostId:this.refs.userPostId.getDOMNode().value,
})
},
<form className="commentForm">
<textarea rows="2" cols="110" placeholder="****Comment Here****" ref="text" /><br />
<input type="text" placeholder="userPostId" ref="userPostId" /> <br />
<button type="button" className="btn btn-success" onClick={this.comment}>Comment</button>
</form>
Change <button type="button" to <button type="submit". Remove the onClick. Instead do <form className="commentForm" onSubmit={onFormSubmit}>. This should catch clicking the button and pressing the return key.
const onFormSubmit = e => {
e.preventDefault();
// send state to server with e.g. `window.fetch`
}
...
<form onSubmit={onFormSubmit}>
...
<button type="submit">Submit</button>
</form>
It's been quite a few years since this question was last answered.
React introduced "Hooks" back in 2017, and "keyCode" has been deprecated.
Now we can write this:
useEffect(() => {
const listener = event => {
if (event.code === "Enter" || event.code === "NumpadEnter") {
console.log("Enter key was pressed. Run your function.");
event.preventDefault();
// callMyFunction();
}
};
document.addEventListener("keydown", listener);
return () => {
document.removeEventListener("keydown", listener);
};
}, []);
This registers a listener on the keydown event, when the component is loaded for the first time. It removes the event listener when the component is destroyed.
Use keydown event to do it:
input: HTMLDivElement | null = null;
onKeyDown = (event: React.KeyboardEvent<HTMLDivElement>): void => {
// 'keypress' event misbehaves on mobile so we track 'Enter' key via 'keydown' event
if (event.key === 'Enter') {
event.preventDefault();
event.stopPropagation();
this.onSubmit();
}
}
onSubmit = (): void => {
if (input.textContent) {
this.props.onSubmit(input.textContent);
input.focus();
input.textContent = '';
}
}
render() {
return (
<form className="commentForm">
<input
className="comment-input"
aria-multiline="true"
role="textbox"
contentEditable={true}
onKeyDown={this.onKeyDown}
ref={node => this.input = node}
/>
<button type="button" className="btn btn-success" onClick={this.onSubmit}>Comment</button>
</form>
);
}
this is how you do it if you want to listen for the "Enter" key.
There is an onKeydown prop that you can use and you can read about it in react doc
and here is a codeSandbox
const App = () => {
const something=(event)=> {
if (event.keyCode === 13) {
console.log('enter')
}
}
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<input type='text' onKeyDown={(e) => something(e) }/>
</div>
);
}
import React, { useEffect, useRef } from 'react';
function Example() {
let inp = useRef();
useEffect(() => {
if (!inp && !inp.current) return;
inp.current.focus();
return () => inp = null;
});
const handleSubmit = () => {
//...
}
return (
<form
onSubmit={e => {
e.preventDefault();
handleSubmit(e);
}}
>
<input
name="fakename"
defaultValue="...."
ref={inp}
type="radio"
style={{
position: "absolute",
opacity: 0
}}
/>
<button type="submit">
submit
</button>
</form>
)
}
Enter code here sometimes in popups it would not work to binding just a form and passing the onSubmit to the form because form may not have any input.
In this case if you bind the event to the document by doing document.addEventListener it will cause problem in another parts of the application.
For solving this issue we should wrap a form and should put a input with what is hidden by css, then you focus on that input by ref it will be work correctly.
If you don't have the form inside <form>, you could use this in componentDidMount():
componentDidMount = () => {
document.addEventListener("keydown", (e) =>
e.code === "Enter" && console.log("my function"))
}
componentDidMount() //<-- remove this, it's just for testing here
useEffect(() => {
const keyEnter = event => {
if (event.key === 'Enter') {
event.preventDefault()
}
}
document.addEventListener('keydown', keyEnter)
return () => {
document.removeEventListener('keydown', keyEnter)
}
}, [])
I've built up on #user1032613's answer and on this answer and created a "on press enter click element with querystring" hook. enjoy!
const { useEffect } = require("react");
const useEnterKeyListener = ({ querySelectorToExecuteClick }) => {
useEffect(() => {
//https://stackoverflow.com/a/59147255/828184
const listener = (event) => {
if (event.code === "Enter" || event.code === "NumpadEnter") {
handlePressEnter();
}
};
document.addEventListener("keydown", listener);
return () => {
document.removeEventListener("keydown", listener);
};
}, []);
const handlePressEnter = () => {
//https://stackoverflow.com/a/54316368/828184
const mouseClickEvents = ["mousedown", "click", "mouseup"];
function simulateMouseClick(element) {
mouseClickEvents.forEach((mouseEventType) =>
element.dispatchEvent(
new MouseEvent(mouseEventType, {
view: window,
bubbles: true,
cancelable: true,
buttons: 1,
})
)
);
}
var element = document.querySelector(querySelectorToExecuteClick);
simulateMouseClick(element);
};
};
export default useEnterKeyListener;
This is how you use it:
useEnterKeyListener({
querySelectorToExecuteClick: "#submitButton",
});
https://codesandbox.io/s/useenterkeylistener-fxyvl?file=/src/App.js:399-407
I have found this to be easier.
Listen for the keyDown event on the input you want to submit by pressing 'Enter" key and handle the submit action with conditional ternary operator as show below in a single line.
This is mostly used on subscribing a newsletter where there's no need of a button to submit.
Hope it helps.
<input
type="email"
placeholder="Email"
onKeyDown={e => e.key === 'Enter' ? handleSubmit : ''} />
You can use <button type='submit'></button> with nothing in the middle.
here is very optimised code
useEffect(() => {
document
.getElementById("Your-element-id")
.addEventListener("keydown", function (event) {
if (event.code === "Enter" || event.code === "NumpadEnter") {
event.preventDefault();
document.getElementById("submit-element").click();
}
});
}, []);
use mousetrap
https://www.npmjs.com/package/mousetrap
https://www.npmjs.com/package/#types/mousetrap
(yeah, I know, unfortunatelly when You use typescript u have to install types aside from basic module)
import {bind} from 'mousetrap';
const handleSubmit = async () => {
// submit func here
};
bind(['enter', 'return'], handleSubmit);
other example of using mousetrap, maybe for other purpose:
bind(['command+k', 'ctrl+k'], function(e) {
highlight([11, 12, 13, 14]);
return false;
});
So, I was looking for some solution around the same scenario where on the login page, after a user hits(press) enter button from keyboard should trigger login process.
You can configure the textbox with one of code,
<input
// rest your code
onKeyPress={ onkeyup }
/>
Please keep in mind I am using react hooks to achieve it, apart from that this link will help you understand more enter key event handler
Try this enter code here:
const enterKye=()=>{
if(e.key==="Enter"){
alert("hello");
}
}
<input type="text" onKeyPress={enterKye}>
You may approach this problem like this.
onKeyPress={e => e.key === 'Enter' && handleFormSubmit}
You can change only button type => button to submit
<form
onSubmit={e => {
e.preventDefault();
handleSubmit(e);
}}
>
<input
name="developers"
defaultValue="submit"
ref={dev}
type="radio"
/>
<button type="submit">
submit
</button>
</form>
for example next React+TS code(add use hooks for state and etc):
type Props = {
...any properties
} & [any other type if need]
//I want notice that input data type of component maybe difference from type of props
const ExampleComponent: React.FC<Props> = (props: [Props or any other type]){
const anySerice = new AnyService();
const handleSubmit = async (eventForm) => {
await anySerice.signUp();
}
const onKeyUp = (event: KeyboardEvent) => {
//you can stay first condition only
if (event.key === 'Enter' || event.charCode === 13) {
handleSubmit(event)
}
}
...other code
return (<Form noValidate validated={validated} className="modal-form-uthorize" onKeyPress={onKeyUp}>
...other components form
</Form>)
}
export default ExampleComponent;
I solved this problem by sent autoFocus property in button
<button autoFocus={true}></button>

Resources