Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2: How to prevent a form from submitting on keypress enter?

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);
      }
    );
  }

}
like image 929
Ole Spaarmann Avatar asked Dec 01 '16 11:12

Ole Spaarmann


People also ask

How to prevent a form from submitting when enter is pressed?

To prevent form submission when the Enter key is pressed in React, use the preventDefault() method on the event object, e.g. event. preventDefault() . The preventDefault method prevents the browser from refreshing the page when the form is submitted.

How to prevent enter key submitting form JS?

You can also use javascript:void(0) to prevent form submission.

How do you make Enter button on form submit in angular?

We can use angular keydown event to use Enter key as our submit key. Add keydown directive inside the form tag. Create a function to submit the form as soon as Enter is pressed. Assign the keydown event to the function.

How to prevent form submit on enter in jQuery?

We use the preventDefault() method with this event to prevent the default action of the form, that is prevent the form from submitting.


2 Answers

Try

<form (keydown.enter)="$event.target.tagName == 'TEXTAREA'" [formGroup]="profileForm" (ngSubmit)="onSubmit($event)">

It will also allow enter in Textareas.

like image 121
Ankit Singh Avatar answered Oct 05 '22 23:10

Ankit Singh


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.

like image 44
Ole Spaarmann Avatar answered Oct 05 '22 22:10

Ole Spaarmann