web-dev-qa-db-fra.com

Angular2 - Mise au point d’une zone de texte sur la charge des composants

Je développe un composant dans Angular2 (Beta 8). Le composant a une zone de texte et une liste déroulante. Je voudrais définir le focus dans la zone de texte dès que le composant est chargé ou sur l'événement de modification de la liste déroulante. Comment pourrais-je y parvenir dans angular2. Voici le code HTML pour le composant. 

<div>
    <form role="form" class="form-horizontal ">        
        <div [ngClass]="{showElement:IsEditMode, hidden:!IsEditMode}">
            <div class="form-group">
                <label class="control-label col-md-1 col-sm-1" for="name">Name</label>
                <div class="col-md-7 col-sm-7">
                    <input id="name" type="text" [(ngModel)]="person.Name" class="form-control" />

                </div>
                <div class="col-md-2 col-sm-2">
                    <input type="button" value="Add" (click)="AddPerson()" class="btn btn-primary" />
                </div>
            </div>
        </div>
        <div [ngClass]="{showElement:!IsEditMode, hidden:IsEditMode}">
            <div class="form-group">
                <label class="control-label col-md-1 col-sm-1" for="name">Person</label>
                <div class="col-md-7 col-sm-7">
                    <select [(ngModel)]="SelectedPerson.Id"  (change)="PersonSelected($event.target.value)" class="form-control">
                        <option *ngFor="#item of PeopleList" value="{{item.Id}}">{{item.Name}}</option>
                    </select>
                </div>
            </div>
        </div>        
    </form>
</div>

61
parag

Cette réponse est inspirée par post Angular 2: focus sur l’élément d’entrée nouvellement ajouté

Étapes pour mettre en évidence l'élément HTML dans Angular2

  1. Importer ViewChildren dans votre composant

    import { Input, Output, AfterContentInit, ContentChild,AfterViewInit, ViewChild, ViewChildren } from 'angular2/core';
    
  2. Déclarez le nom de la variable de modèle local pour le code HTML pour lequel vous souhaitez définir le focus

  3. Implémentez la fonction ngAfterViewInit () ou d’autres hooks de cycle de vie appropriés
  4. Voici le morceau de code que j'ai utilisé pour définir le focus

    ngAfterViewInit() {vc.first.nativeElement.focus()}
    
  5. Ajoutez l'attribut #input à l'élément DOM auquel vous souhaitez accéder.

///This is TypeScript
import {Component, Input, Output, AfterContentInit, ContentChild,
  AfterViewChecked, AfterViewInit, ViewChild,ViewChildren} from 'angular2/core';

export class AppComponent implements AfterViewInit,AfterViewChecked { 
   @ViewChildren('input') vc;
  
   ngAfterViewInit() {            
        this.vc.first.nativeElement.focus();
    }
  
 }
<div>
    <form role="form" class="form-horizontal ">        
        <div [ngClass]="{showElement:IsEditMode, hidden:!IsEditMode}">
            <div class="form-group">
                <label class="control-label col-md-1 col-sm-1" for="name">Name</label>
                <div class="col-md-7 col-sm-7">
                    <input #input id="name" type="text" [(ngModel)]="person.Name" class="form-control" />

                </div>
                <div class="col-md-2 col-sm-2">
                    <input type="button" value="Add" (click)="AddPerson()" class="btn btn-primary" />
                </div>
            </div>
        </div>
        <div [ngClass]="{showElement:!IsEditMode, hidden:IsEditMode}">
            <div class="form-group">
                <label class="control-label col-md-1 col-sm-1" for="name">Person</label>
                <div class="col-md-7 col-sm-7">
                    <select [(ngModel)]="SelectedPerson.Id"  (change)="PersonSelected($event.target.value)" class="form-control">
                        <option *ngFor="#item of PeopleList" value="{{item.Id}}">{{item.Name}}</option>
                    </select>
                </div>
            </div>
        </div>        
    </form>
</div>

57
parag

L'utilisation d'un attribut autofocus HTML5 simple fonctionne pour le scénario "au chargement"

 <input autofocus placeholder="enter text" [(ngModel)]="test">

ou 

<button autofocus (click)="submit()">Submit</button>

http://www.w3schools.com/TAgs/att_input_autofocus.asp

59
Nikhil Nambiar

La question initiale demandait un moyen de définir le focus initialement, OR pour le définir ultérieurement, en réponse à un événement. Il semble que la bonne façon de procéder consiste à créer une directive d'attribut pouvant être définie pour tout élément d'entrée, puis à utiliser un événement personnalisé pour déclencher en toute sécurité la méthode de focus sur cet élément d'entrée. Pour cela, commencez par créer la directive:

import { Directive, Input, EventEmitter, ElementRef, Renderer, Inject } from '@angular/core';

@Directive({
    selector: '[focus]'
})
export class FocusDirective {
    @Input('focus') focusEvent: EventEmitter<boolean>;

    constructor(@Inject(ElementRef) private element: ElementRef, private renderer: Renderer) {
    }

    ngOnInit() {
        this.focusEvent.subscribe(event => {
            this.renderer.invokeElementMethod(this.element.nativeElement, 'focus', []);
        });
    }
}

Notez qu'il utilise renderer.invokeElementMethod sur le nativeElement, qui est sécurisé pour les travaux Web. Notez également que focusEvent est déclaré en tant qu'entrée. 

Ajoutez ensuite les déclarations suivantes au composant Angular 2 qui contient le modèle dans lequel vous souhaitez utiliser la nouvelle directive pour définir le focus sur un élément d’entrée:

public focusSettingEventEmitter = new EventEmitter<boolean>();

ngAfterViewInit() { // ngOnInit is NOT the right lifecycle event for this.
    this.focusSettingEventEmitter.emit(true);
}
setFocus(): void {
  this.focusSettingEventEmitter.emit(true);
}

N'oubliez pas d'importer EventEmitter au-dessus du composant, comme ceci:

import { Component, EventEmitter } from '@angular/core';

et dans le modèle de ce composant, définissez le nouvel attribut [focus] comme suit:

<input id="name" type="text" name="name" 
    [(ngModel)]="person.Name" class="form-control"
    [focus]="focusSettingEventEmitter">

Enfin, dans votre module, importez et déclarez la nouvelle directive comme ceci:

import { FocusDirective } from './focus.directive';

@NgModule({
    imports: [ BrowserModule, FormsModule ],
    declarations: [AppComponent, AnotherComponent, FocusDirective ],
    bootstrap: [ AppComponent ]
})

Pour récapituler: la fonction ngAfterViewInit provoquera l’émission du nouvel EventEmitter, et puisque nous avons affecté cet émetteur à l’attribut [focus] de l’élément input de notre modèle, nous avons déclaré cet EventEmitter comme entrée de la nouvelle directive et appelé le focus méthode dans la fonction de flèche que nous avons passée à la souscription à cet événement, l'élément input recevra le focus une fois le composant initialisé et chaque fois que setFocus est appelé.

J'ai eu le même besoin dans ma propre application, et cela a fonctionné comme annoncé. Merci beaucoup aux personnes suivantes: http://blog.thecodecampus.de/angular-2-set-focus-element/

23
Kent Weigel
<input id="name" type="text" #myInput />
{{ myInput.focus() }}

c'est le moyen le plus simple et le meilleur, car le code "myInput.focus ()" est exécuté après la création de l'entrée

17
Sergey Gurin

Voir Angulaire 2: focus sur le nouvel élément d’entrée ajouté pour savoir comment définir le focus.

Pour "en charge", utilisez le rappel de cycle de vie ngAfterViewInit().

4

J'ai eu un problème légèrement différent. J'ai travaillé avec des entrées dans un modal et cela m'a rendu fou. Aucune des solutions proposées n'a fonctionné pour moi.

Jusqu'à ce que j'ai trouvé ce problème: https://github.com/valor-software/ngx-bootstrap/issues/1597

Ce brave gars m'a laissé entendre que ngx-bootstrap modal a une configuration de focus. Si cette configuration n'est pas définie sur false, le modal sera mis au point après l'animation et vous ne pouvez rien faire d'autre.

Mettre à jour:

Pour définir cette configuration, ajoutez l'attribut suivant au div modal: 

[config]="{focus: false}"

Mise à jour 2:

Pour forcer le focus sur le champ de saisie, j’ai écrit une directive et défini le focus dans chaque cycle AfterViewChecked tant que le champ de saisie a la classe ng-intouched.

 ngAfterViewChecked() {
    // This dirty hack is needed to force focus on an input element of a modal.
    if (this.el.nativeElement.classList.contains('ng-untouched')) {
        this.renderer.invokeElementMethod(this.el.nativeElement, 'focus', []);
    }
}
2
FireGnome

En outre, cela peut être fait de manière dynamique comme si ...

<input [id]="input.id" [type]="input.type" [autofocus]="input.autofocus" />

Où l'entrée est

const input = {
  id: "my-input",
  type: "text",
  autofocus: true
};
0
SoEzPz

Je n'ai pas eu beaucoup de chance avec beaucoup de ces solutions sur tous les navigateurs. C'est la solution qui a fonctionné pour moi.

Pour les changements de routeur:

router.events.subscribe((val) => {
    setTimeout(() => {
        if (this.searchElement) {
            this.searchElement.nativeElement.focus();
        }
    }, 1);
})

Puis ngAfterViewInit() pour le scénario de charge.

0
rtaft