web-dev-qa-db-fra.com

Comment définir par programme le focus sur FormControl créé dynamiquement dans Angular2

Je ne semble pas être en mesure de mettre l'accent sur un champ de saisie dans FormGroup ajouté dynamiquement:

addNewRow(){
    (<FormArray>this.modalForm.get('group1')).Push(this.makeNewRow());
    // here I would like to set a focus to the first input field
    // say, it is named 'textField'

    // but <FormControl> nor [<AbstractControl>][1] dont seem to provide 
    // either a method to set focus or to access the native element
    // to act upon
}

Comment définir le focus sur angular2 FormControl ou AbstractControl?

14
user776686

Vous ne pouvez pas définir un FormControl ou AbstractControl, car ce ne sont pas des éléments DOM. Ce que vous devez faire, c'est avoir une référence à eux, en quelque sorte, et appeler .focus() là-dessus. Vous pouvez y parvenir via ViewChildren (dont les documents de l'API sont inexistants actuellement, 2016-12-16).

Dans votre classe de composants:

import { ElementRef, ViewChildren } from '@angular/core';

// ...imports and such

class MyComponent {
    // other variables
    @ViewChildren('formRow') rows: ElementRef;

    // ...other code
    addNewRow() {
        // other stuff for adding a row
        this.rows.first().nativeElement.focus();
    }
}

Si vous vouliez vous concentrer sur le dernier enfant ...this.rows.last().nativeElement.focus()

Et dans votre modèle quelque chose comme:

<div #formRow *ngFor="let row in rows">
    <!-- form row stuff -->
</div>

MODIFIER:

J'ai en fait trouvé un CodePen de quelqu'un qui fait ce que vous cherchez https://codepen.io/souldreamer/pen/QydMNG

16
gonzofish

Pour Angular 5, en combinant toutes les réponses ci-dessus comme suit:

Code pertinent du composant:

 import { AfterViewInit, QueryList, ViewChildren, OnDestroy } from '@angular/core';
 import { Subscription } from 'rxjs/Subscription';

 // .. other imports

 export class MyComp implements AfterViewInit, OnDestroy {
   @ViewChildren('input') rows: QueryList<any>;
   private sub1:Subscription = new Subscription();
   //other variables ..

 // changes to rows only happen after this lifecycle event so you need
 // to subscribe to the changes made in rows.  
 // This subscription is to avoid memory leaks
 ngAfterViewInit() {
   this.sub1 = this.rows.changes.subscribe(resp => {
     if (this.rows.length > 1){
       this.rows.last.nativeElement.focus();
     }
   });
  }

  //memory leak avoidance
  ngOnDestroy(){
    this.sub1.unsubscribe();
  }


   //add a new input to the page
   addInput() {
     const formArray = this.form.get('inputs') as FormArray;

     formArray.Push(
        new FormGroup(
        {input: new FormControl(null, [Validators.required])}
     ));
    return true;
   }

 // need for dynamic adds of elements to re 
 //focus may not be needed by others
 trackByFn(index:any, item:any){
    return index;
 }

La logique du modèle ressemble à ceci:

 <div formArrayName="inputs" class="col-md-6 col-12" 
     *ngFor="let inputCtrl of form.get('phones').controls; 
             let i=index; trackBy:trackByFn">
     <div [formGroupName]="i">
        <input #input type="text" class="phone" 
             (blur)="addRecord()"
             formControlName="input" />
     </div>
 </div>

Dans mon modèle, j'ajoute un enregistrement sur flou, mais vous pouvez tout aussi facilement configurer un bouton pour ajouter dynamiquement le champ de saisie suivant. La partie importante est qu'avec ce code, le nouvel élément obtient le focus comme souhaité.

Laissez-moi savoir ce que vous pensez

7
Ken

Ceci est la méthode sûre recommandée par angulaire

@Component({
  selector: 'my-comp',
  template: `
    <input #myInput type="text" />
    <div> Some other content </div>
  `
})
export class MyComp implements AfterViewInit {
  @ViewChild('myInput') input: ElementRef;

  constructor(private renderer: Renderer) {}

  ngAfterViewInit() {
    this.renderer.invokeElementMethod(this.input.nativeElement,    
    'focus');
  }
}
1
Omkar Yadav