wake-up-neo.com

Wie kann ich ein Element in einer Komponentenvorlage auswählen?

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?

435
Aman Gupta

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);
}

StackBlitz-Beispiel

  • @ ViewChild () unterstützt Anweisungen oder Komponententypen als Parameter oder den Namen (String) einer Vorlagenvariablen.
  • @ ViewChildren () unterstützt auch eine Liste von Namen als durch Kommas getrennte Liste (derzeit sind keine Leerzeichen zulässig @ViewChildren('var1,var2,var3')).
  • @ ContentChild () und @ ContentChildren () machen dasselbe, aber im hellen DOM (<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

Siehe Zugriff auf übermittelte Inhalte

808

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

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) {
    // ...
  }
}

Beispiel aktualisiert, um mit der neuesten Version zu arbeiten

Für weitere Details zum nativen Element hier

46
gdi2290

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.

18
Neil T.

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) {
}
12
jsgoupil

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.

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

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) { }
}
3
Aluan Haddad

verwenden Sie diese Option, um das nächste Geschwister zu finden

event.source._elementRef.nativeElement.nextElementSibling
1
Apoorv

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;
}
1
Sai Goud