angular - Kako mogu odabrati element u predlošku komponente?


Zna li netko kako doći do elementa definiranog u predlošku komponente? Polymer to olakšava s $ i $$.

Samo sam se pitao kako to napraviti u Angularu.

Uzmite primjer iz vodiča:

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

Kako da dohvatim ili dobijem referencu na p ili input element iz definicije klase?

Odgovor #1

Umjesto da se ubrizgava ElementRef i koristi querySelector ili slično od tamo, može se umjesto toga koristiti deklarativni način za izravan pristup elementima u prikazu:

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

element

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

Primjer StackBlitz

  • @ViewChild() podržava tip direktive ili komponente kao parametar, ili ime (string) varijable predloška.
  • @ViewChildren() također podržava popis imena odvojenih zarezom (trenutno nisu dopušteni razmaci @ViewChildren('var1,var2,var3')).
  • @ContentChild() i @ContentChildren() rade isto, ali u light DOM-u (<ng-content> projektirani elementi).

potomci

@ContentChildren() je jedini koji vam također omogućuje da upitujete potomke

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

čitati

Ako postoje komponenta i direktive, parametar read omogućuje vam da odredite koja instanca bi trebala biti vraćena.

Na primjer, ViewContainerRef koji je potreban dinamički kreiranim komponentama umjesto zadane ElementRef

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

pretplati se na promjene

Iako se djeca prikaza postavljaju tek kada se pozove ngAfterViewInit(), a djeca sadržaja tek kada se pozove ngAfterContentInit(), ako želite pretplatiti se na promjene rezultata upita, to bi trebalo učiniti u 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));
}

direktan pristup DOM-u

može upitavati samo DOM elemente, ali ne i instance komponenti ili direktiva:

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

dobiti proizvoljni projektirani sadržaj

Pogledajte sadržaj koji je transkludiran

Odgovor #2

Možete dobiti pristup DOM elementu putem ElementRef tako da ga ubacite u konstruktor vaše komponente:

constructor(private myElement: ElementRef) { ... }

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

Odgovor #3

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

Primjer ažuriran da radi s najnovijom verzijom

Za više detalja o izvornom elementu, ovdje

Odgovor #4

Angular 4+: Koristite renderer.selectRootElement s CSS selektorom za pristup elementu.

Imam obrazac koji u početku prikazuje unos e-pošte. Nakon što se e-pošta unese, obrazac će se proširiti kako bi im omogućio nastavak dodavanja informacija vezanih uz njihov projekt. Međutim, ako oni nisu postojeći klijent, obrazac će uključivati odjeljak za adresu iznad odjeljka s informacijama o projektu.

Do sada, dio unosa podataka nije razdvojen na komponente, pa se sekcije upravljaju pomoću *ngIf direktiva. Trebam postaviti fokus na polje bilješki o projektu ako su postojeći klijent, ili na polje za ime ako su novi.

Pokušao sam rješenja bez uspjeha. Međutim, Ažuriranje 3 u ovom odgovoru dalo mi je polovicu konačnog rješenja. Druga polovica došla je iz odgovora MatteoNY-a u ovoj raspravi. Rezultat je ovo:

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

Budući da jedino što radim je postavljanje fokusa na element, ne moram se brinuti o otkrivanju promjena, pa zapravo mogu poziv renderer.selectRootElement izvršiti izvan Angulara. Budući da moram dati novim sekcijama vrijeme da se renderiraju, odjeljak elementa je omotan u timeout kako bi renderirajući threadovi imali vremena da stignu prije nego što se pokuša odabir elementa. Nakon što je sve to postavljeno, jednostavno mogu pozvati element koristeći osnovne CSS selektore.

Znam da se ovaj primjer prvenstveno bavio događajem fokusa, ali meni je teško što se ovo ne može koristiti u drugim kontekstima.

AZURIRANJE: Angular je ukinuo podršku za Renderer u Angularu 4 i potpuno ga uklonio u Angularu 9. Ovo rješenje ne bi trebalo biti pogođeno migracijom na Renderer2. Molimo pogledajte ovaj link za dodatne informacije: Migracija s Renderer na Renderer2

Odgovor #5

Za ljude koji pokušavaju dohvatiti instancu komponente unutar *ngIf ili *ngSwitchCase, možete slijediti ovaj trik.

Stvorite init direktivu.

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

Izvezite svoju komponentu s imenom poput myComponent

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

Upotrijebite ovaj predložak za dobivanje ElementRef I MyComponent instance

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

Upotrijebite ovaj kod u TypeScriptu

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

Odgovor #6

uvezite dekorator ViewChild iz @angular/core, ovako:

HTML kod:

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

TS kod:

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

class TemplateFormComponent {

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

sada možete koristiti objekt 'myForm' za pristup bilo kojem elementu unutar njega u klasi.

Izvor

Odgovor #7

 */
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*/
        };
    }
}

Povezani članci