Angular 2: How to prevent a form from submitting on keypress enter?
Solution 1
Try
<form (keydown.enter)="$event.target.tagName == 'TEXTAREA'" [formGroup]="profileForm" (ngSubmit)="onSubmit($event)">
It will also allow enter
in Textarea
s.
Solution 2
So the answer was actually quite simple... It wasn't Event.preventDefault()
since I was listening for Enter on the input field and not the button. Removing type="submit"
from the button
wasn't enough since all buttons are type submit by default. The only change necessary was on the button element, adding type="button"
explicitly and adding a (click)
listener:
<button type="button" (click)="onSubmit()" class="btn btn-primary pull-right" [disabled]="!profileForm.valid">Save</button>
The only kind-of problem: Now submitting the form with enter never works. Would be a tiny bit more elegant to only prevent enter from submitting the form when the focus is in the autocomplete input field.
Edit:
To only prevent enter from submitting the form when the cursor is in the autocomplete field can be achieved by using Ankit Singh's solution and modifying it a bit:
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()" method="post" (keydown.enter)="$event.target.id != 'skill_string'" *ngIf="!showSuccessMessage">
(Note: The condition has to return false to prevent the default action to be triggered)
Of course we then need our regular submit button again (without the click event attached, or the form will submit twice):
<button type="submit" class="btn btn-primary pull-right" [disabled]="!profileForm.valid">Save</button>
You could also check the event.target.classList
if you want to use a .autocomplete
class. Or move the checking logic to a function into which you pass the $event
.
Solution 3
Events in Angular 2 behave like normal DOM events. To capture the event object, pass $event
as a parameter in the event callback from the template:
Html:
<button (keyup.enter)="skillsHandleEnter($event, skillString)"></button>
JavaScript using Event.preventDefault():
@Component(...)
class MyComponent {
skillsHandleEnter(event, skillString) {
event.preventDefault();
// ... your logic
}
}
![Ole Spaarmann](https://i.stack.imgur.com/oyJIX.jpg?s=256&g=1)
Ole Spaarmann
Updated on August 02, 2020Comments
-
Ole Spaarmann almost 4 years
I have a form with one field that acts as autocomplete. If the user enters a word and presses enter, the content of the field should be added to a list below the field.
The problem: When the user hits enter, naturally the whole form is being submitted.
I already
return false
on the function that handles the keypress. But the form seems to be submitted even before this function is called.How do I prevent this from happening?
The basic form:
<div id="profileForm"> <form [formGroup]="profileForm" (ngSubmit)="onSubmit()" method="post" *ngIf="!showSuccessMessage"> <div class="row"> <div class="form-group col-xs-12 col-sm-6"> <label for="first_name">My Skills</label> <div class="autocomplete"> <input formControlName="skill_string" [(ngModel)]="skillString" name="skill_string" type="text" class="form-control" id="skill_string" placeholder="Comma separated" (keyup.enter)="skillsHandleEnter(skillString)"> <ul class="autocomplete-list" *ngIf="skillHints.length > 0"> <li class="list-item" *ngFor="let skill of skillHints" (click)="addSkillFromAutocomplete(skill)">{{skill}}</li> </ul> </div> <div id="skill-cloud" class="tag-cloud"> <span class="skill-tag tag label label-success" *ngFor="let skill of selectedSkills" (click)="removeSkill(skill)">{{skill}} x</span> </div> </div> </div> <div class="row"> <hr> <div class="form-group submit-group"> <div class="col-sm-12"> <button type="submit" class="btn btn-primary pull-right" [disabled]="!profileForm.valid">Save</button> </div> </div> </div> </form> </div>
The basic component (I stripped a lot of the logic for posting it here):
import { Component, OnInit } from '@angular/core'; import { FormGroup, FormBuilder } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { Subscription } from 'rxjs/Rx'; import 'rxjs/add/operator/debounceTime'; import * as _ from 'lodash'; import { MemberService } from '../shared/index'; @Component({ moduleId: module.id, selector: 'signup', templateUrl: 'signup.component.html', styleUrls: ['signup.component.css'] }) export class SignupComponent implements OnInit { private profileForm:FormGroup; private validation_errors:Array<any>; private selectedSkills:Array<string>; private skillHints:Array<string>; private skillString:string; constructor(private route: ActivatedRoute, private formBuilder: FormBuilder, private memberService: MemberService, private router: Router ) { this.selectedSkills = []; this.skillHints = []; this.skillString = ''; // Set up form this.profileForm = this.formBuilder.group({ skill_string: [''] }); } ngOnInit(): any { // Do something } updateSelectedSkills(skillString:string):void { if(skillString) ) { let cleanString = skillString.trim().replace(/[ ]{2,}/g, ' '); this.selectedSkills = _.compact(this.selectedSkills.concat(cleanString.split(','))); this.skillString = ''; this.skillHints = []; } } skillsHandleEnter(skillString:string):void { console.log("ENTER"); this.updateSelectedSkills(skillString); return false; } autocompleteSkills(term:string):void { this.memberService.autocompleteSkills(term).subscribe( res => { this.skillHints = []; for(let i = 0; i < res.data.length; i++) { this.skillHints.push(res.data[i].name); } } ); } addSkillFromAutocomplete(skillString:string):void { this.selectedSkills.push(skillString); this.memberProfile.skill_string = ''; this.skillHints = []; this.skillString = ''; } onSubmit():void { this.memberService.saveProfile(this.memberProfile, this.selectedSkills).subscribe( res => { console.log(res); } ); } }
-
Günter Zöchbauer over 7 yearsJust a hint. Returning
false
also calls$event.preventDefault()
-
Ankit Singh over 7 years@GünterZöchbauer thanks for reminding, lets make it more compact then
-
Günter Zöchbauer over 7 yearsBut now it doesn't return
false
. Perhaps"!!($event.target.tagName == 'TEXTAREA)'"
(not sure about this!!
operator - I'm not using JS/TS myself - only Dart) -
Ankit Singh over 7 yearsI just tested, it's working for me.
$event.target.tagName == 'TEXTAREA'
is always a boolean, eitherfalse
ortrue
-
Günter Zöchbauer over 7 yearsAh, sorry. You are right, I assumed this to be an assignment. Perhaps I need new glasses :D
-
Ankit Singh over 7 yearshaha, it's alright. I have learned enough from you to excuse you even without asking :)
-
Lukas Jelinek over 5 yearsI would also add BUTTON,
$event.target.tagName == 'TEXTAREA' || $event.target.tagName == 'BUTTON'
. Can happen you go through the form using TAB key and and up on button, then enter would not work. -
Kevin Beal over 4 yearsYou don't need or want to use
preventDefault()
on a textarea, and it wouldn't work even if it was an<input>
. You can't use preventDefault like that. The form will completely ignore it.