web-dev-qa-db-fra.com

Angular 2: Comment empêcher un formulaire de se soumettre à la frappe au clavier?

J'ai un formulaire avec un champ qui agit comme une saisie semi-automatique. Si l'utilisateur entre un mot et appuie sur entrer, le contenu du champ doit être ajouté à une liste située sous le champ.

Le problème: lorsque l'utilisateur tape, tout le formulaire est bien sûr soumis.

J'ai déjà return false sur la fonction qui gère la frappe. Mais le formulaire semble être soumis avant même que cette fonction ne soit appelée.

Comment puis-je empêcher que cela se produise?

La forme de base:

<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>

Le composant de base (j'ai enlevé beaucoup de logique pour l'afficher ici):

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

}
12
Ole Spaarmann

Essayer

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

Cela permettra également à enter dans Textareas.

13
Ankit Singh

La réponse était donc plutôt simple… Ce n'était pas Event.preventDefault() puisque j'écoutais Enter sur le champ de saisie et non le bouton. Supprimer type="submit" de la button n'était pas suffisant, car tous les boutons sont de type submit par défaut. La seule modification nécessaire concernait l'élément button, en ajoutant type="button" explicitement et en ajoutant un écouteur (click):

<button type="button" (click)="onSubmit()" class="btn btn-primary pull-right" [disabled]="!profileForm.valid">Save</button>

Le seul type de problème: Soumettre le formulaire avec enter ne fonctionne jamais. Serait un petit peu plus élégant pour empêcher seulement enter de soumettre le formulaire lorsque le focus est dans le champ de saisie semi-automatique.

Modifier:

Pour empêcher uniquement enter de soumettre le formulaire lorsque le curseur est dans le champ de saisie semi-automatique, utilisez la solution d'Ankit Singh et modifiez-la un peu:

<form [formGroup]="profileForm" (ngSubmit)="onSubmit()" method="post" (keydown.enter)="$event.target.id != 'skill_string'" *ngIf="!showSuccessMessage">

(Remarque: la condition doit renvoyer false pour empêcher le déclenchement de l'action par défaut.)

Bien sûr, nous avons à nouveau besoin de notre bouton d'envoi régulier (sans l'événement click joint, sinon le formulaire sera envoyé deux fois):

<button type="submit" class="btn btn-primary pull-right" [disabled]="!profileForm.valid">Save</button>

Vous pouvez également vérifier le event.target.classList si vous souhaitez utiliser une classe .autocomplete. Ou déplacez la logique de contrôle vers une fonction dans laquelle vous transmettez le $event.

6
Ole Spaarmann

Les événements dans Angular 2 se comportent comme des événements DOM normaux. Pour capturer l'objet événement, transmettez $event en tant que paramètre dans le rappel d'événement à partir du modèle:

Html:

<button (keyup.enter)="skillsHandleEnter($event, skillString)"></button>

JavaScript utilisant Event.preventDefault () :

@Component(...)
class MyComponent {
  skillsHandleEnter(event, skillString) {
    event.preventDefault();
    // ... your logic
  }
}
2
Yosvel Quintero

Empêcher un formulaire de soumettre le enter ou en cliquant sur buttonname __

<textarea (keydown.enter)="provoked($event)"></textarea>

<button (keydown.enter)="provoked($event)" (click)="provoked($event)"></button>

provoked($event) {
   $event.preventDefault()
}

au cas où vous auriez besoin de transmettre des données à la méthode, essayez

<textarea (keydown.enter)="provoked($event, data)"></textarea>

<button (keydown.enter)="provoked($event, data)" (click)="provoked($event, data)"></button>

provoked($event, data) {
   $event.preventDefault()

   // process the data here
}
0
WasiF