angular - Ako môžem vybrať prvok v šablóne komponentu?


Vie niekto, ako získať prístup k elementu definovanému v šablóne komponentu? Polymer to uľahčuje pomocou $ a $$.

Len som sa zaujímal, ako na to ísť v Angular.

Vezmite si príklad z tutoriálu:

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

Ako môžem zachytiť alebo získať referenciu na element p alebo input z vnútorného definovania triedy?

Odpoveď č. 1

Namiesto injektovania ElementRef a používania querySelector alebo podobného odtiaľto, je možné použiť deklaratívny spôsob na priamy prístup k prvkom vo view:

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

prvok

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

Príklad StackBlitz

  • @ViewChild() podporuje ako parameter typ direktívy alebo komponentu, alebo meno (reťazec) šablónovej premennej.
  • @ViewChildren() tiež podporuje zoznam mien ako zoznam oddelený čiarkami (momentálne nie sú povolené medzery @ViewChildren('var1,var2,var3')).
  • @ContentChild() a @ContentChildren() robia to isté, ale v light DOM (projekčné prvky <ng-content>).

potomkovia

@ContentChildren() je jediný, ktorý vám umožňuje aj dotazovať sa na potomkov

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

čítať

Ak existuje komponenta a direktívy, parameter read vám umožňuje určiť, ktorá inštancia by mala byť vrátená.

Napríklad ViewContainerRef, ktorý je potrebný pre dynamicky vytvorené komponenty namiesto predvoleného ElementRef

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

odber zmien

Aj keď sú pohľadové deti nastavené až po zavolaní ngAfterViewInit() a obsahové deti sú nastavené až po zavolaní ngAfterContentInit(), ak chcete odoberať zmeny výsledku dotazu, malo by sa to robiť v 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));
}

priamy prístup k DOM

môže dotazovať iba DOM elementy, ale nie inštancie komponentov alebo direktív:

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

získať ľubovoľný premietnutý obsah

Pozri prístup k zaclenenému obsahu

Odpoveď č. 2

Na získanie referencie na DOM element môžete použiť ElementRef vložením do konštruktora vašej komponenty:

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

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

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

Príklad aktualizovaný tak, aby fungoval s najnovšou verziou

Pre viac informácií o natívnom prvku, tu

Odpoveď č. 4

Angular 4+: Použite renderer.selectRootElement s CSS selektorom na prístup k elementu.

Mám formulár, ktorý pôvodne zobrazuje vstup pre e-mail. Po zadaní e-mailu sa formulár rozšíri, aby mohli pokračovať v pridávaní informácií týkajúcich sa ich projektu. Ak však nie sú existujúcim klientom, formulár bude obsahovať sekciu adresy nad sekciou informácií o projekte.

K dnešnému dňu časť zadávania údajov nebola rozdelená na komponenty, takže sekcie sa riadia pomocou direktív *ngIf. Potrebujem nastaviť fokus na pole poznámok k projektu, ak ide o existujúceho klienta, alebo na pole krstného mena, ak je nový.

Vyskúšal som riešenia bez úspechu. Avšak, Aktualizácia 3 v tejto odpovedi mi dala polovicu konečného riešenia. Druhú polovicu som získal z odpovede MatteoNY v tejto diskusii. Výsledok je tento:

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

Keďže jediné, čo robím, je nastavenie zamerania na prvok, nemusím sa zaoberať zisťovaním zmien, takže môžem vlastne spustiť volanie renderer.selectRootElement mimo Angularu. Pretože musím dať novým sekciám čas na vykreslenie, je časť prvku zabalená do časového oneskorenia, aby mali vykresľovacie vlákna čas dohnať predtým, než sa pokúsi o výber prvku. Keď je všetko pripravené, môžem jednoducho zavolať prvok pomocou základných CSS selektorov.

Viem, že tento príklad sa zaoberal predovšetkým udalosťou zamerania, ale je pre mňa ťažké, že toto nemôže byť použité v iných kontextoch.

AKTUALIZÁCIA: Angular zrušil podporu pre Renderer v Angular 4 a úplne ho odstránil v Angular 9. Toto riešenie by nemalo byť ovplyvnené migráciou na Renderer2. Pre viac informácií prosím navštívte tento odkaz: Migrácia Renderer na Renderer2

Odpoveď č. 5

Pre ľudí, ktorí sa snažia získať inštanciu komponentu vo vnútri *ngIf alebo *ngSwitchCase, môžete nasledovať tento trik.

Vytvorte init direktívu.

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

Exportujte svoju komponentu s názvom, ako napríklad myComponent

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

Použite túto šablónu na získanie inštancie ElementRef A MyComponent

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

Použite tento kód v TypeScripte

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

Odpoveď č. 6

importujte dekorátor ViewChild z @angular/core, takto:

HTML kód:

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

Kód TS:

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

class TemplateFormComponent {

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

Teraz môžete použiť objekt 'myForm' na prístup k akémukoľvek prvku v ňom v triede.

Zdroj

Odpoveď č. 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*/
        };
    }
}

Súvisiace články