React: check the pressed key on form submit - node.js

I am using React (and Material UI), and I am trying to submit a form. As default by pressing enter when focused on the text field, the form submits. I want it to only happen when I press the Submit button.
The form
<Box component="form" onSubmit={handleSubmit} noValidate sx={{ mt: 1 }}>
<TextField
margin="normal"
required
fullWidth
id="title"
label="Title"
name="title"
autoComplete="title"
autoFocus
defaultValue={title}
/>
<TextArea setData={setData} data={JSON.parse(description)} />
<Button
type="submit"
fullWidth
variant="contained"
sx={{ mt: 3, mb: 2 }}
>
Finish
</Button>
<Link href="/">
Back
</Link>
</Box>
The submit function
const handleSubmit = async (e) =>
{
e.preventDefault();
console.log(e)
//
}

This is default behavior since you have your code in a form. It shouldn't matter to you where the users cursor is. This is necessary for screen readers and for basic user experience.
To focus on the next field, the user should be able to tab to the next field.
e.preventDefault is to keep the page from reloading on submit.

I just added onKeyPress to the TextField and checked if the pressed key is equal to Enter
<TextField
margin="normal"
required
fullWidth
id="title"
label="Title"
name="title"
autoComplete="title"
onKeyPress={(e) => { e.key === 'Enter' && e.preventDefault(); }} //<----
autoFocus
/>

Related

Styled Components in React: <Form /> onSubmit handler does not work

The Form Component is of type styled.form`` and is defined outside the component on the bottom of the file. The issue: The onSubmit event handler does not work. Official docs don't have anything on onSubmit.
const submitHandler = e => {
e.preventDefault()
console.log(e) // nothing appears in console
}
/// ... in JSX:
<Form onSubmit={submitHandler} >
<Input placeholder="YouTube URL" required name="input" onChange={changeHandler} />
<Button type="submit" >
<Icon /> <Span>Add Song</Span>
</Button>
</Form>
//... styled form defined at the bottom of the file below export default statement:
const Form = styled.form`
display: flex;
`
A Solution that I have found is to attach the submitHandler to an onClick event of a button inside a form. I'm not sure about that as I have never in the past used the button for submitHandlers (and I don't think it even works in pure React).
So, this would work:
<Button type="submit" onClick={submitHandler} >Submit</Button>
The problem is with the button. You have the <Button> component implemented as a <div> styled component. Having type="submit" on a <div> has no effect as far as the form is concerned. That's why the submit event never got fired.
So, you can change your code as follows:
const Button = styled.button
remove onClick from the button and change the onSubmit simply to submitHandler:
<div>
<Form onSubmit={submitHandler}>
<Input
placeholder="Paste YouTube URL here"
required
name="input"
onChange={changeHandler}
/>
<Button type="submit">
<Icon /> <Span>Add Song</Span>
</Button>
</Form>
</div>
You will see the results in the UI, as the form will start applying validation (because of the required attribute on the input), and also in the console where the handler will log.

How do I set up a comment reply feature in react.js in these codes?

So, I am using react, nodejs and mongodb to build a basic blog application.
So far, I have been able to add the comment feature and users can create, delete and edit comments. But I wanted to add the ability to reply to a comment. I added a 'Reply' text inside the area where I mapped the array of comments in my react.js component. So, when you click on the 'Reply' it toggles the textbox for reply. That means on first click, the textbox to reply to that specific comment shows up, on second click, that textbox hides.
The problem now is that the toggle is working for all the mapped array of comments. I am trying to assign the specific '_id' to the 'Reply' text and pass it to the textbox for the user to write their reply to that specific comment using the '_id'. This should prevent the reply textbox from toggling for all the comments at the same time. How best can I get this done? Here are my codes:
The useState that hides and shows the textbox
const [showReply, setShowReply] = useState(false)
The function that toggles the useState
const handleShowReplyComment = (id) =>{
console.log(id)
if(id){
setShowReply(!showReply)
console.log(id)
}
}
This function picks the '_id' of the comment that I clicked. But how to pass that '_id' to the textbox is my challenge.
return (
<div className="comment">
<h5 className='users-comment'>Users comments</h5>
{comments.map((singleComment, index)=>{
console.log(singleComment)
const {author, commentdescription, _id, createdAt} = singleComment
return(
<>
{updateComment == _id ?
<div className='comment-div' key={_id} >
<textarea className='comment-wrapper' type='text'
onChange={(e) => setCommentDescription(e.target.value)} value={commentdescription2}>
</textarea>
<button className={isLoading ? 'comment-btn-no-cursor comment-btn': 'comment-btn'}onClick={() => handleCommentUpdate(_id)}>Update Post</button>
{error && <p>what happened?</p> }
</div>
:
<div className='displayed-comments'key={_id}>
<div className="commentPic">
<img className="user-pics" src={PF + singleComment.author.profilePicture} alt="" />
</div>
<div className="comment-info">
<div className="comment-author-div">
<div className='comment-author-date-info'>
<h4 className="comment-author">{singleComment.author.username}</h4>
<p className="comment-date">{new Date(singleComment.createdAt).toDateString()}
</p>
</div>
{
singleComment.author.username == user?.username && <div className="comment-edit-delete-div">
<i className="singlePostIcon fas fa-edit" onClick={() => {setUpdateComment(_id); setCommentDescription(commentdescription)}} ></i>
<i className={isLoading? "cursor-not-allowed singlePostIcon far fa-trash-alt":"singlePostIcon far fa-trash-alt" } onClick={() => handleCommentDelete(_id)} ></i>
</div>
}
</div>
<p className="comment-content">{singleComment.commentdescription}</p>
<div>
</div>
<h5 className="reply-comment" onClick={() => handleShowReplyComment(_id)}>Reply</h5> //this is the text with the toggle onClick function that toggles the useState called 'showReply'
{showReply && <div className='reply-div'>//this is the textbox with the useState 'showReply'.
<textarea className='comment-wrapper '>
</textarea>
</div>}
</div>
</div>
}
</>
)
})}
</div>
)

Redux-Form Field appearing just a line on the bottom of inputs instead of box. Is there a work-through to get the box?

I am using redux-form and setting up a sign-up form. The fields are not like that appear in sandbox preview on their documentation site.
I tried to provide bootstrap classNames form-group, form-control for field and input respectively but it appears to be default action. Just a bar on bottom.
Actually I have a blue background so I need a completely white box so user can see the grey placeholder of an input field.
My renderFields method:
renderFields(){
return _.map(formFields, ({name,type,placeholder}) =>{
return(
<Field
key={name}
type= {type}
name={name}
placeholder={placeholder}
component={SignupField}
/>
);
})
And Field method:
<div className="form-group">
<input type={type} className="form-control" {...input}
placeholder={placeholder}/>
<div className="red-text" style={{marginBottom:"30px"}}>
{touched && error}
</div>
</div>
And form:
<form class="user-forms" onSubmit=
{this.props.handleSubmit(values=>this.submitForm(values))}>
{this.renderFields()}
<button className="btnSubmit btn btn-primary"
type="submit">Create Account
</button>
</form>
I expect a box for each input & not line at bottom.
OK I was using materialize css that caused the interference.

How to create onSubmit with Material-UI

So I'm fairly new to node.js / react / material-ui. I've been following a guide to try setting up a website and have been getting on pretty well. I decided to include material-ui for snazzy components (not part of the guide) and then got stuck because I can't seem to fire custom functions whilst using a themed ui.
With the below code, I can create everything fine if I ditch the 'classes' props. I can add my function and everything works. But I obviously lose all my styling if I do this.
const styles = theme => ({
// Styling - omitted
});
const Login = (props) => {
const {classes} = props;
return(
<div>
<Paper className={classes.root}>
<form className={classes.container} noValidate autoComplete="off">
<TextField
id="email"
label="Email"
className={classes.textField}
InputProps={{
className: classes.input
}}
type="email"
name="email"
autoComplete="email"
margin="normal"
variant="outlined"
required
autoFocus
/>
<TextField
id="outlined"
label="Password"
className={classes.textField}
InputProps={{
className: classes.input
}}
type="password"
autoComplete="current-password"
margin="normal"
variant="outlined"
required
/>
<Typography className={classes.divider} />
<Button
type="submit"
variant="contained"
color="inherit"
className={classes.button}
>
Login
</Button>
</form>
</Paper>
</div>
);
}
Login.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(Login);
I'm trying to combine the styling as well as being able to fire a custom function to submit the form data. Does anyone have any thoughts?
The class property/ styles shouldn't have any effect on form submission custom function. If you think that ditching the 'class props' you can get a custom function to work - post your code so we can help you further. [Your code is missing submit function]
Here is one way to add custom submit function
const Login = (props) => {
const {classes} = props;
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
function handleSubmit(event) {
event.preventDefault();
console.log( 'Email:', email, 'Password: ', password);
// You should see email and password in console.
// ..code to submit form to backend here...
}
return( <div >
<Paper className={classes.root}>
<form className={classes.container} onSubmit={handleSubmit} >
<TextField
....
value={email}
onInput={ e=>setEmail(e.target.value)}
.....
/>
<TextField
....
value={password}
onInput={ e=>setPassword(e.target.value)}
....
/>
<Typography className={classes.divider} />
<Button
type="submit"
....
className={classes.button}
>
Login
</Button>
</form>
</Paper>
</div>
);

Angular6 Material Dialog prevent from closing when pressing enter

I have a login dialog and want to prevent it from closing automatically when enter is pressed.
To be more specific, when the user put the credential and pressed enter and the response for credential came back as error, I want the dialog to stay (so I can show them some error message and let the user try once again).
So this is what I did:
export class LoginComponent {
constructor(public dialogRef: MatDialogRef<LoginComponent>) { }
onSubmit(): void {
this.authService.login(...)
.subscribe(res => {
...
},
error => {
this.dialogRef.disableClose = true;
}
}
}
this.dialogRef.disableClose = true; still closes the dialog even though the response came back as error.
How should I do this?
Edit
login.component.ts
<mat-toolbar>
<span>Login</span>
</mat-toolbar>
<mat-card class="my-card">
<div *ngIf="error" style="color: red;">{{error}}</div><br />
<form (ngSubmit)="onSubmit()" [formGroup]="loginForm">
<mat-card-content>
<mat-form-field appearance="outline" class="full-width">
<mat-label>Email</mat-label>
<input matInput placeholder="Email"
formControlName="email"
[formControl]="emailFormControl"
[errorStateMatcher]="matcher" />
<mat-error *ngIf="emailFormControl.hasError('email') && !emailFormControl.hasError('required')">
Enter valid email address
</mat-error>
<mat-error *ngIf="emailFormControl.hasError('required')">
Required field
</mat-error>
</mat-form-field>
<mat-form-field appearance="outline" class="full-width">
<mat-label>Password</mat-label>
<input matInput type="password"
placeholder="Password"
formControlName="password"
[formControl]="passwordFormControl"
[errorStateMatcher]="matcher" />
<mat-error *ngIf="passwordFormControl.hasError('required')">
Required field
</mat-error>
</mat-form-field>
</mat-card-content>
<mat-card-actions>
<button mat-raised-button (click)="onNoClick()" color="primary">Close</button>
<button mat-raised-button
[disabled]="!(loginForm.controls.email.valid && loginForm.controls.password.valid)"
color="accent">
Login
</button>
</mat-card-actions>
</form>
</mat-card>
login.component.ts
onSubmit(): void {
if (this.loginForm.invalid) {
return;
}
this.authService.login(this.loginForm.controls.email.value, this.loginForm.controls.password.value)
.subscribe(res => {
if (res) {
alert("logged in");
}
},
error => {
this.error = 'Error! Plese try again.';
}
);
}
I believe it's because your "CLOSE" button, is not set to type="button", and I THINK that's the first element that has focus, so when pressing enter, you are entering that button, which by default, will submit the form. Add type="button" and that should solve it.
Also for the record, the latest version of angular material has md-button automatically add type="button" by default (unless you specify type="submit") to avoid this type of situation
Use this
<mat-card-actions>
<button mat-raised-button type="button" (click)="onNoClick()" color="primary">Close</button>
<button mat-raised-button type="submit"
[disabled]="!(loginForm.controls.email.valid && loginForm.controls.password.valid)"
color="accent">
Login
</button>
</mat-card-actions>

Resources