web-dev-qa-db-fra.com

Comment sélectionner un élément dans un modèle de composant?

Est-ce que quelqu'un sait comment se procurer un élément défini dans un modèle de composant? Polymer simplifie vraiment l'utilisation de $ et $$.

Je me demandais simplement comment s'y prendre dans Angular.

Prenez l'exemple du tutoriel:

import {Component} from '@angular/core'

@Component({
    selector:'display'
    template:`
     <input #myname(input)="updateName(myname.value)"/>
     <p>My name : {{myName}}</p>
    `

})
export class DisplayComponent {
    myName: string = "Aman";
    updateName(input: String) {
        this.myName = input;
    }
}

Comment attraper une référence de l'élément p ou input dans la définition de classe?

435
Aman Gupta

Au lieu d'injecter ElementRef et d'utiliser querySelector ou similaire à partir de là, une méthode déclarative peut être utilisée pour accéder directement aux éléments de la vue:

<input #myname>
@ViewChild('myname') input; 

élément

ngAfterViewInit() {
  console.log(this.input.nativeElement.value);
}

exemple StackBlitz

  • @ ViewChild () prend en charge le type de directive ou de composant en tant que paramètre ou le nom (chaîne) d'une variable de modèle.
  • @ ViewChildren () supporte également une liste de noms sous forme de liste séparée par des virgules (aucun espace n'est actuellement autorisé @ViewChildren('var1,var2,var3')).
  • @ ContentChild () et @ ContentChildren () font la même chose mais à la lumière du DOM (<ng-content> éléments projetés).

descendants

@ContentChildren() est le seul qui permet de rechercher également des descendants

@ContentChildren(SomeTypeOrVarName, {descendants: true}) someField; 

{descendants: true} devrait être la valeur par défaut mais n'est pas en version 2.0.0 finale et c'est considéré comme un bogue
Ceci a été corrigé dans 2.0.1

lire

S'il existe un composant et des directives, le paramètre read permet de spécifier l'instance à renvoyer.

Par exemple, ViewContainerRef requis par les composants créés dynamiquement à la place de la valeur par défaut ElementRef

@ViewChild('myname', { read: ViewContainerRef }) target;

souscrire des modifications

Même si les enfants de vue ne sont définis que lorsque ngAfterViewInit() est appelé et que les enfants de contenu ne sont définis que lorsque ngAfterContentInit() est appelé, si vous souhaitez vous abonner aux modifications du résultat de la requête, cette opération doit être effectuée dans ngOnInit().

https://github.com/angular/angular/issues/9689#issuecomment-229247134

@ViewChildren(SomeType) viewChildren;
@ContentChildren(SomeType) contentChildren;

ngOnInit() {
  this.viewChildren.changes.subscribe(changes => console.log(changes));
  this.contentChildren.changes.subscribe(changes => console.log(changes));
}

accès direct au DOM

peut uniquement interroger des éléments DOM, mais pas des composants ou des instances de directive:

export class MyComponent {
  constructor(private elRef:ElementRef) {}
  ngAfterViewInit() {
    var div = this.elRef.nativeElement.querySelector('div');
    console.log(div);
  }

  // for transcluded content
  ngAfterContentInit() {
    var div = this.elRef.nativeElement.querySelector('div');
    console.log(div);
  }
}

obtenir du contenu projeté arbitraire

Voir Accéder au contenu inclus

808
Günter Zöchbauer

Vous pouvez obtenir un descripteur sur l'élément DOM via ElementRef en l'injectant dans le constructeur de votre composant:

constructor(myElement: ElementRef) { ... }

Docs: https://angular.io/docs/ts/latest/api/core/index/ElementRef-class.html

191
Brocco
import { Component, ElementRef, OnInit } from '@angular/core';

@Component({
  selector:'display',
  template:`
   <input (input)="updateName($event.target.value)">
   <p> My name : {{ myName }}</p>
  `
})
class DisplayComponent implements OnInit {
  constructor(public element: ElementRef) {
    this.element.nativeElement // <- your direct element reference 
  }
  ngOnInit() {
    var el = this.element.nativeElement;
    console.log(el);
  }
  updateName(value) {
    // ...
  }
}

Exemple mis à jour pour fonctionner avec la dernière version

Pour plus de détails sur l'élément natif, here

46
gdi2290

Angular 4 + : Utilisez renderer.selectRootElement avec un sélecteur CSS pour accéder à l'élément.

J'ai un formulaire qui affiche initialement une entrée de courrier électronique. Une fois le courrier électronique entré, le formulaire sera développé pour leur permettre de continuer à ajouter des informations relatives à leur projet. Cependant, s'ils ne sont pas un client existant, le formulaire comportera une section d'adresse au-dessus de la section d'informations du projet.

A ce jour, la partie entrée de données n'a pas été divisée en composants, les sections sont donc gérées avec des directives * ngIf. Je dois mettre l'accent sur le champ de notes de projet s'il s'agit d'un client existant ou sur le champ de prénom s'il est nouveau.

J'ai essayé les solutions sans succès. Cependant, la mise à jour 3 dans this réponse m'a fourni la moitié de la solution éventuelle. L'autre moitié provient de la réponse de MatteoNY dans le fil this . Le résultat est le suivant:

import { NgZone, Renderer } from '@angular/core';

constructor(private ngZone: NgZone, private renderer: Renderer) {}

setFocus(selector: string): void {
    this.ngZone.runOutsideAngular(() => {
        setTimeout(() => {
            this.renderer.selectRootElement(selector).focus();
        }, 0);
    });
}

submitEmail(email: string): void {
    // Verify existence of customer
    ...
    if (this.newCustomer) {
        this.setFocus('#firstname');
    } else {
        this.setFocus('#description');
    }
}

Étant donné que je ne fais que focaliser l'attention sur un élément, je n'ai pas besoin de me préoccuper de la détection des modifications pour pouvoir lancer l'appel à renderer.selectRootElement en dehors de Angular. Parce que je dois donner le temps de rendre aux nouvelles sections, la section des éléments est encapsulée dans un délai d'expiration pour permettre aux threads de rendu de se rattraper avant que la sélection de l'élément ne soit tentée. Une fois tout cela configuré, je peux simplement appeler l'élément à l'aide des sélecteurs CSS de base.

Je sais que cet exemple portait principalement sur l'événement central, mais il est difficile pour moi que cela ne puisse pas être utilisé dans d'autres contextes.

18
Neil T.

Vous pouvez suivre cette astuce pour les personnes qui tentent de saisir l'instance de composant dans un *ngIf ou *ngSwitchCase.

Crée une directive init.

import {
    Directive,
    EventEmitter,
    Output,
    OnInit,
    ElementRef
} from '@angular/core';

@Directive({
    selector: '[init]'
})
export class InitDirective implements OnInit {
    constructor(private ref: ElementRef) {}

    @Output() init: EventEmitter<ElementRef> = new EventEmitter<ElementRef>();

    ngOnInit() {
        this.init.emit(this.ref);
    }
}

Exportez votre composant avec un nom tel que myComponent

@Component({
    selector: 'wm-my-component',
    templateUrl: 'my-component.component.html',
    styleUrls: ['my-component.component.css'],
    exportAs: 'myComponent'
})
export class MyComponent { ... }

tilisez ce modèle pour obtenir l'instance ElementRef AND MyComponent

<div [ngSwitch]="type">
    <wm-my-component
           #myComponent="myComponent"
           *ngSwitchCase="Type.MyType"
           (init)="init($event, myComponent)">
    </wm-my-component>
</div>

tilisez ce code dans TypeScript

init(myComponentRef: ElementRef, myComponent: MyComponent) {
}
12
jsgoupil

importer le décorateur ViewChild de @angular/core, comme suit:

Code HTML:

<form #f="ngForm"> 
  ... 
  ... 
</form>

Code TS:

import { ViewChild } from '@angular/core';

class TemplateFormComponent {

  @ViewChild('f') myForm: any;
    .
    .
    .
}

maintenant, vous pouvez utiliser l'objet 'myForm' pour accéder à n'importe quel élément de la classe.

Source

9
Hany
 */
import {Component,ViewChild} from '@angular/core' /*Import View Child*/

@Component({
    selector:'display'
    template:`

     <input #myname (input) = "updateName(myname.value)"/>
     <p> My name : {{myName}}</p>

    `
})
export class DisplayComponent{
  @ViewChild('myname')inputTxt:ElementRef; /*create a view child*/

   myName: string;

    updateName: Function;
    constructor(){

        this.myName = "Aman";
        this.updateName = function(input: String){

            this.inputTxt.nativeElement.value=this.myName; 

            /*assign to it the value*/
        };
    }
}
8
Eng.Gabr

Je voudrais ajouter que si vous utilisez ElementRef, comme le recommandent toutes les réponses, vous rencontrerez immédiatement le problème suivant: ElementRef a une déclaration de type horrible qui ressemble à

export declare class ElementRef {
  nativeElement: any;
}

c'est stupide dans un environnement de navigateur où nativeElement est un HTMLElement.

Pour contourner ce problème, vous pouvez utiliser la technique suivante

import {Inject, ElementRef as ErrorProneElementRef} from '@angular/core';

interface ElementRef {
  nativeElement: HTMLElement;
}

@Component({...}) export class MyComponent {
  constructor(@Inject(ErrorProneElementRef) readonly elementRef: ElementRef) { }
}
3
Aluan Haddad

pour obtenir le prochain frère immédiatement, utilisez cette

event.source._elementRef.nativeElement.nextElementSibling
1
Apoorv

Sélection de l'élément cible dans la liste. Il est facile de sélectionner un élément particulier dans la liste des mêmes éléments.

code composant:

export class AppComponent {
  title = 'app';

  listEvents = [
    {'name':'item1', 'class': ''}, {'name':'item2', 'class': ''},
    {'name':'item3', 'class': ''}, {'name':'item4', 'class': ''}
  ];

  selectElement(item: string, value: number) {
    console.log("item="+item+" value="+value);
    if(this.listEvents[value].class == "") {
      this.listEvents[value].class='selected';
    } else {
      this.listEvents[value].class= '';
    }
  }
}

code html:

<ul *ngFor="let event of listEvents; let i = index">
   <li  (click)="selectElement(event.name, i)" [class]="event.class">
  {{ event.name }}
</li>

code css:

.selected {
  color: red;
  background:blue;
}
1
Sai Goud