Weiß jemand, wie er an ein in einer Komponentenvorlage definiertes Element gelangt? Polymer macht es mit dem $
und $$
wirklich einfach.
Ich habe mich nur gefragt, wie ich in Angular vorgehen soll.
Nehmen Sie das Beispiel aus dem Tutorial:
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;
}
}
Wie erhalte ich eine Referenz des Elements p
oder input
in der Klassendefinition?
Anstatt ElementRef
einzufügen und querySelector
oder ähnliches von dort aus zu verwenden, kann stattdessen eine deklarative Methode verwendet werden, um direkt auf Elemente in der Ansicht zuzugreifen:
<input #myname>
@ViewChild('myname') input;
element
ngAfterViewInit() {
console.log(this.input.nativeElement.value);
}
@ViewChildren('var1,var2,var3')
).<ng-content>
projizierte Elemente).Nachkommen
@ContentChildren()
ist die einzige, mit der auch Nachkommen abgefragt werden können
@ContentChildren(SomeTypeOrVarName, {descendants: true}) someField;
{descendants: true}
sollte der Standard sein, ist aber nicht in 2.0.0 final und es ist als Fehler angesehen
Dies wurde in 2.0.1 behoben
lies
Wenn eine Komponente und Direktiven vorhanden sind, kann mit dem Parameter read
angegeben werden, welche Instanz zurückgegeben werden soll.
Zum Beispiel ViewContainerRef
, das von dynamisch erstellten Komponenten anstelle des Standardwerts ElementRef
benötigt wird
@ViewChild('myname', { read: ViewContainerRef }) target;
Änderungen abonnieren
Obwohl untergeordnete Ansichten nur festgelegt werden, wenn ngAfterViewInit()
aufgerufen wird, und untergeordnete Inhalte nur festgelegt werden, wenn ngAfterContentInit()
aufgerufen wird, sollte dies in ngOnInit()
erfolgen, wenn Sie Änderungen des Abfrageergebnisses abonnieren möchten.
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));
}
direkter DOM-Zugriff
kann nur DOM-Elemente abfragen, aber keine Komponenten oder Direktiveninstanzen:
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);
}
}
Beliebigen projizierten Inhalt erhalten
Sie können ein Handle für das DOM-Element über ElementRef
erstellen, indem Sie es in den Konstruktor Ihrer Komponente einfügen:
constructor(myElement: ElementRef) { ... }
Dokumente: 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) {
// ...
}
}
Beispiel aktualisiert, um mit der neuesten Version zu arbeiten
Für weitere Details zum nativen Element hier
Winkel 4 + : Verwenden Sie renderer.selectRootElement
mit einem CSS-Selektor, um auf das Element zuzugreifen.
Ich habe ein Formular, in dem zunächst eine E-Mail-Eingabe angezeigt wird. Nachdem die E-Mail eingegeben wurde, wird das Formular erweitert, damit sie weiterhin Informationen zu ihrem Projekt hinzufügen können. Wenn es sich jedoch nicht um einen vorhandenen Kunden handelt , enthält das Formular einen Adressabschnitt über dem Projektinformationsabschnitt.
Da der Dateneingabeabschnitt noch nicht in Komponenten aufgeteilt wurde, werden die Abschnitte mit * ngIf-Direktiven verwaltet. Ich muss den Fokus auf das Feld Projektnotizen legen, wenn es sich um einen vorhandenen Kunden handelt, oder auf das Feld Vorname, wenn es sich um einen neuen Kunden handelt.
Ich habe die Lösungen ohne Erfolg ausprobiert. Mit Update 3 in this answer habe ich jedoch die Hälfte der möglichen Lösung erhalten. Die andere Hälfte kam von MatteoNYs Antwort in this thread. Das Ergebnis ist folgendes:
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');
}
}
Da ich mich nur auf ein Element konzentriere, muss ich mich nicht um die Änderungserkennung kümmern, damit ich den Aufruf von renderer.selectRootElement
tatsächlich außerhalb von Angular ausführen kann. Da ich den neuen Abschnitten Zeit zum Rendern geben muss, wird der Elementabschnitt in eine Zeitüberschreitung eingeschlossen, damit die Rendering-Threads Zeit zum Aufholen haben, bevor die Elementauswahl versucht wird. Sobald alles eingerichtet ist, kann ich das Element einfach mit einfachen CSS-Selektoren aufrufen.
Ich weiß, dass sich dieses Beispiel hauptsächlich mit dem Fokusereignis befasste, aber es fällt mir schwer, dass dies in anderen Kontexten nicht verwendet werden kann.
Wenn Sie versuchen, die Komponenteninstanz in einem *ngIf
oder *ngSwitchCase
zu erfassen, können Sie diesen Trick ausführen.
Erstellen Sie eine init
-Anweisung.
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);
}
}
Exportieren Sie Ihre Komponente mit einem Namen wie myComponent
@Component({
selector: 'wm-my-component',
templateUrl: 'my-component.component.html',
styleUrls: ['my-component.component.css'],
exportAs: 'myComponent'
})
export class MyComponent { ... }
Verwenden Sie diese Vorlage, um die Instanz ElementRef
AND MyComponent
abzurufen.
<div [ngSwitch]="type">
<wm-my-component
#myComponent="myComponent"
*ngSwitchCase="Type.MyType"
(init)="init($event, myComponent)">
</wm-my-component>
</div>
Verwenden Sie diesen Code in TypeScript
init(myComponentRef: ElementRef, myComponent: MyComponent) {
}
importieren Sie den ViewChild
-Dekorator aus @angular/core
wie folgt:
HTML Quelltext:
<form #f="ngForm">
...
...
</form>
TS-Code:
import { ViewChild } from '@angular/core';
class TemplateFormComponent {
@ViewChild('f') myForm: any;
.
.
.
}
jetzt können Sie mit dem Objekt 'myForm' auf jedes Element in der Klasse zugreifen.
*/
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*/
};
}
}
Ich möchte hinzufügen, dass, wenn Sie ElementRef
verwenden, wie in allen Antworten empfohlen, Sie sofort auf das Problem stoßen, dass ElementRef
eine schreckliche Typdeklaration hat, die so aussieht
export declare class ElementRef {
nativeElement: any;
}
dies ist in einer Browserumgebung, in der nativeElement ein HTMLElement
ist, dumm.
Um dies zu umgehen, können Sie die folgende Technik verwenden
import {Inject, ElementRef as ErrorProneElementRef} from '@angular/core';
interface ElementRef {
nativeElement: HTMLElement;
}
@Component({...}) export class MyComponent {
constructor(@Inject(ErrorProneElementRef) readonly elementRef: ElementRef) { }
}
verwenden Sie diese Option, um das nächste Geschwister zu finden
event.source._elementRef.nativeElement.nextElementSibling
Zielelement aus der Liste auswählen. Es ist einfach, ein bestimmtes Element aus der Liste derselben Elemente auszuwählen.
Komponentencode:
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= '';
}
}
}
HTML-Code:
<ul *ngFor="let event of listEvents; let i = index">
<li (click)="selectElement(event.name, i)" [class]="event.class">
{{ event.name }}
</li>
CSS-Code:
.selected {
color: red;
background:blue;
}