J'ai un composant qui a un élément p
. Son événement onClick
le changera en textarea
afin que l'utilisateur puisse modifier les données. Ma question est:
J'ai essayé d'utiliser "ElementRef" et "@ViewChild ()", mais il me semble qu'il manque quelque chose:
// ------ THE CLASS
@ViewChild('tasknoteId') taskNoteRef:ElementRef;
noteEditMode: boolean = false;
get isShowNote (){
return !this.noteEditMode && this.todo.note ? true : false;
}
taskNote: string;
toggleNoteEditMode () {
this.noteEditMode = !this.noteEditMode;
this.renderer.invokeElementMethod(this.taskNoteRef.nativeElement,'focus');
}
// ------ THE COMPONENT
<span class="the-insert">
<form [hidden]="!noteEditMode && todo.note">
<textarea #tasknoteId id="tasknote"
name="tasknote"
[(ngModel)]="todo.note"
placeholder="{{ notePlaceholder }}"
style="background-color:pink"
(blur)="updateNote()" (click)="toggleNoteEditMode()"
[autofocus]="noteEditMode"
[innerHTML]="todo.note">
</textarea>
</form>
</span>
Mise à jour (à l'aide du moteur de rendu):
Notez que le service Renderer d'origine est maintenant obsolète en faveur de Renderer2.
comme sur doc officiel de Renderer2
En outre, comme l'a souligné @ GünterZöchbauer:
En fait, utiliser ElementRef est très bien. Également utiliser ElementRef.nativeElement avec Renderer2, c'est bien. Ce qui est déconseillé, c'est d'accéder directement aux propriétés de ElementRef.nativeElement.xxx.
Vous pouvez y parvenir en utilisant elementRef
ainsi que par ViewChild
. Cependant, il n'est pas recommandé d'utiliser elementRef
pour les raisons suivantes:
comme indiqué par documentation officielle ng2 .
elementRef
(accès direct):export class MyComponent {
constructor (private _elementRef : elementRef) {
this._elementRef.nativeElement.querySelector('textarea').focus();
}
}
ViewChild
( meilleure approche ):<textarea #tasknote name="tasknote" [(ngModel)]="taskNote" placeholder="{{ notePlaceholder }}"
style="background-color: pink" (blur)="updateNote() ; noteEditMode = false " (click)="noteEditMode = false"> {{ todo.note }} </textarea> // <-- changes id to local var
export class MyComponent implements AfterViewInit {
@ViewChild('tasknote') input: ElementRef;
ngAfterViewInit() {
this.input.nativeElement.focus();
}
}
renderer
:export class MyComponent implements AfterViewInit {
@ViewChild('tasknote') input: ElementRef;
constructor(private renderer: Renderer2){
}
ngAfterViewInit() {
//using selectRootElement instead of depreaced invokeElementMethod
this.renderer.selectRootElement(this.input["nativeElement"]).focus();
}
}
Angular 2.0.0 Final:
J'ai constaté que l'utilisation d'un paramètre ViewChild
est le moyen le plus fiable de définir le focus du contrôle de formulaire initial:
@ViewChild("myInput")
set myInput(_input: ElementRef | undefined) {
if (_input !== undefined) {
setTimeout(() => {
this._renderer.invokeElementMethod(_input.nativeElement, "focus");
}, 0);
}
}
Le poseur est d'abord appelé avec une valeur undefined
, suivie d'un appel avec un ElementRef
initialisé.
Exemple de travail et source complète ici: http://plnkr.co/edit/u0sLLi?p=preview
Utilisation de TypeScript 2.0.3 Final/RTM, Angular 2.0.0 Final/RTM et Chrome 53.0.2785.116 m (64 bits).
UPDATE pour Angular 4 +
Renderer
est déconseillé en faveur de Renderer2
, mais Renderer2
n'a pas la invokeElementMethod
. Vous devrez accéder directement au DOM pour définir le focus comme dans input.nativeElement.focus()
.
Je constate toujours que l'approche de ViewChild setter fonctionne le mieux. Lors de l'utilisation de AfterViewInit
j'obtiens parfois l'erreur read property 'nativeElement' of undefined
.
@ViewChild("myInput")
set myInput(_input: ElementRef | undefined) {
if (_input !== undefined) {
setTimeout(() => { //This setTimeout call may not be necessary anymore.
_input.nativeElement.focus();
}, 0);
}
}