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?
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);
}
@ViewChildren('var1,var2,var3')
).<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
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
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
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.
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) {
}
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.
*/
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*/
};
}
}
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) { }
}
pour obtenir le prochain frère immédiatement, utilisez cette
event.source._elementRef.nativeElement.nextElementSibling
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;
}