컴포넌트 템플릿에서 요소를 어떻게 선택할 수 있습니까?


516

구성 요소 템플릿에 정의 된 요소를 얻는 방법을 아는 사람이 있습니까? 폴리머는 $and로 정말 쉬워집니다 $$.

Angular에서 어떻게 진행해야하는지 궁금했습니다.

튜토리얼에서 예제를 보자.

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

클래스 정의 내에서 p또는 input요소 의 참조를 잡거나 참조를 얻으려면 어떻게합니까 ?

답변:


937

거기에서 주입 ElementRef하거나 사용 querySelector하거나 유사한 대신에 , 선언적인 방법을 사용하여 뷰의 요소에 직접 액세스 할 수 있습니다.

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

요소

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

StackBlitz 예제

  • @ViewChild () 는 지시문 또는 구성 요소 유형을 매개 변수 또는 템플리트 변수의 이름 (문자열)으로 지원합니다.
  • @ViewChildren () 은 또한 이름 목록을 쉼표로 구분 된 목록으로 지원합니다 (현재 공백은 허용되지 않음 @ViewChildren('var1,var2,var3')).
  • @ContentChild ()@ContentChildren () 은 동일하지만 가벼운 DOM ( <ng-content>투사 요소)에서 작동합니다.

자손

@ContentChildren() 자손을 쿼리 할 수있는 유일한 사람입니다.

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

{descendants: true}기본값이어야하지만 2.0.0 최종 버전이 아니며 버그로 간주
됩니다. 2.0.1에서 수정되었습니다.

읽다

구성 요소 및 지시문이있는 경우 read매개 변수를 통해 리턴 할 인스턴스를 지정할 수 있습니다.

예를 들어 ViewContainerRef기본값 대신 동적으로 생성 된 구성 요소에 필요한ElementRef

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

구독 변경

뷰 하위 ngAfterViewInit()는 호출 될 때만 설정 되고 컨텐츠 하위는 호출 될 때만 설정되지만 ngAfterContentInit()조회 결과의 변경 사항을 구독하려면 다음에서 수행해야합니다.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));
}

직접적인 DOM 액세스

DOM 요소 만 쿼리 할 수 ​​있지만 컴포넌트 또는 지시문 인스턴스는 조회 할 수 없습니다.

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

임의의 투영 된 컨텐츠를 얻는다

변환 된 컨텐츠 액세스를 참조하십시오.


12
각진 팀은 ElementRef를 사용하지 말 것을 권장합니다. 이것이 더 나은 솔루션입니다.
Honorable Chow

7
실제로 input또한입니다. ElementRef그러나 호스트에서 쿼리하는 대신 실제로 원하는 요소에 대한 참조를 얻습니다 ElementRef.
Günter Zöchbauer

32
실제로 사용하는 ElementRef것이 좋습니다. 또한 ElementRef.nativeElementwith를 사용 하는 Renderer것이 좋습니다. 무엇 권장하지 않습니다 것은 의 속성에 접근입니다 ElementRef.nativeElement.xxx직접.
Günter Zöchbauer 2016 년

2
@Natanael 나는 이것이 명시 적으로 문서화되어 있는지 여부를 알지 못하지만 DOM 직접 액세스를 피해야하는 문제 또는 다른 토론 (앵귤러 팀 구성원들)에서도 정기적으로 언급됩니다. DOM에 직접 액세스하면 (속성 및 메소드에 액세스 ElementRef.nativeElement)하는 것) Angulars 서버 측 렌더링 및 WebWorker 기능을 사용할 수 없습니다 (다가오는 오프라인 템플릿 컴파일러가 중단되는지는 모르겠지만 – 그렇지 않습니다)
Günter Zöchbauer 2016 년

10
위에서 읽기 섹션 에서 언급 한 것처럼 ViewChild가있는 요소의 nativeElement를 가져 오려면 다음을 수행해야합니다. @ViewChild('myObj', { read: ElementRef }) myObj: ElementRef;
jsgoupil

203

ElementRef컴포넌트의 생성자에 DOM 요소를 삽입 하여 DOM 요소에 대한 핸들을 얻을 수 있습니다 .

constructor(myElement: ElementRef) { ... }

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


1
@Brocco 답변을 업데이트 할 수 있습니까? ElementRef사라진 이후 현재 솔루션을보고 싶습니다 .
Jefftopia

23
ElementRef사용할 수 있습니다 (다시?).
Günter Zöchbauer

10
링크 DOM에 직접 액세스해야하는 경우이 API를 최후의 수단 으로 사용하십시오 . 대신 Angular에서 제공하는 템플릿 및 데이터 바인딩을 사용하십시오. 또는 네이티브 요소에 대한 직접 액세스가 지원되지 않는 경우에도 안전하게 사용할 수있는 API를 제공하는 렌더러를 살펴보십시오. 직접 DOM 액세스를 사용하면 애플리케이션과 렌더링 계층간에 긴밀한 연결이 이루어 지므로 두 애플리케이션을 분리하여 웹 워커에 애플리케이션을 배포 할 수 없습니다.
sandeep talabathula

@sandeeptalabathula 타사 라이브러리에서 부동 날짜 선택기 구성 요소를 첨부 할 요소를 찾는 더 좋은 옵션은 무엇입니까? 나는 이것이 원래의 질문이 아니라는 것을 알고 있지만 DOM에서 요소를 찾는 것이 모든 시나리오에서 나쁘다는 것을 알 수 있습니다.
John

13
@ 존 아 .. 알았어. 이것을 시도해보고 this.element.nativeElement.querySelector('#someElementId')ElementRef를 이와 같은 생성자에 전달할 수 있습니다 . private element: ElementRef, Import lib ...import { ElementRef } from '@angular/core';
sandeep talabathula

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

최신 버전으로 작동하도록 업데이트 된 예

기본 요소에 대한 자세한 내용은 여기를 참조하십시오.


20

Angular 4+ : renderer.selectRootElementCSS 선택기와 함께 사용 하여 요소에 액세스합니다.

처음에는 이메일 입력을 표시하는 양식이 있습니다. 이메일을 입력하면 양식이 확장되어 프로젝트와 관련된 정보를 계속 추가 할 수 있습니다. 그러나 기존 고객 이 아닌 경우 양식에는 프로젝트 정보 섹션 위에 주소 섹션이 포함됩니다.

현재 데이터 입력 부분이 구성 요소로 분리되지 않았으므로 섹션은 * ngIf 지시문으로 관리됩니다. 기존 클라이언트 인 경우 프로젝트 노트 필드에 초점을 설정하고 새로운 클라이언트 인 경우 이름 필드에 초점을 설정해야합니다.

나는 성공하지 않고 솔루션을 시도했다. 그러나에 업데이트 3 대답은 나에게 최종 솔루션의 절반을했다. 나머지 절반은 스레드 에서 MatteoNY의 응답에서 비롯되었습니다 . 결과는 다음과 같습니다.

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

내가하고있는 유일한 일은 요소에 초점을 맞추는 것이므로 변경 감지에 신경 쓸 필요가 없으므로 실제로 renderer.selectRootElementAngular 외부로 전화를 걸 수 있습니다 . 새 섹션에 렌더링 시간을 제공해야하므로 요소 선택을 시도하기 전에 렌더링 스레드 시간을 따라 잡을 수 있도록 요소 섹션이 시간 초과로 래핑됩니다. 모든 설정이 완료되면 기본 CSS 선택기를 사용하여 요소를 간단히 호출 할 수 있습니다.

이 예제는 주로 포커스 이벤트를 다루었지만 다른 상황에서는 사용할 수 없다는 것이 어렵습니다.


Renderer 클래스는 Angular 4.3.0부터 사용되지 않습니다. angular.io/api/core/Renderer
Jamie

15

*ngIf또는의 내부에서 구성 요소 인스턴스를 가져 오려는 *ngSwitchCase경우이 트릭을 수행 할 수 있습니다.

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

다음과 같은 이름으로 구성 요소를 내 보냅니다. myComponent

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

이 템플릿을 사용하여 ElementRefAND MyComponent인스턴스 를 가져옵니다.

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

TypeScript에서이 코드를 사용하십시오.

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

12

에서 ViewChild데코레이터를 가져옵니다 @angular/core.

HTML 코드 :

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

TS 코드 :

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

class TemplateFormComponent {

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

이제 'myForm'객체를 사용하여 클래스 내의 모든 요소에 액세스 할 수 있습니다.

Source


그러나 구성 요소 클래스의 템플릿 요소에 거의 액세스 할 필요가 없으며 각도 논리를 올바르게 이해하면됩니다.
Hany

3
아무것도 사용하지 마십시오. 유형은 ElementRef
Johannes입니다.

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

10
이 코드에 대한 설명을 제공해주세요. 설명없이 단순히 코드 덤프는 권장하지 않습니다.
rayryeng

5
작동하지 않습니다. @ViewChild 주석을 통해 설정된 속성은 ngAfterViewInit 수명주기 이벤트 후에 만 ​​사용할 수 있습니다. 이 경우 생성자의 값에 액세스하면 정의되지 않은 값이 생성 inputTxt됩니다.
David M.

중앙 7을 사용하면 완벽하게 작동했습니다.
MizAkita

5

참고 :이 각도 6 적용으로 이상하지 않습니다ElementRef되었다ElementRef<T>T유형을 나타내는nativeElement.

ElementRef모든 답변에서 권장하는대로를 사용하는 경우 ElementRef다음과 같은 끔찍한 유형 선언이있는 문제가 즉시 발생한다는 것을 추가 하고 싶습니다.

export declare class ElementRef {
  nativeElement: any;
}

nativeElement가 인 브라우저 환경에서는 바보입니다 HTMLElement.

이 문제를 해결하려면 다음 기술을 사용할 수 있습니다

import {Inject, ElementRef as ErrorProneElementRef} from '@angular/core';

interface ElementRef {
  nativeElement: HTMLElement;
}

@Component({...}) export class MyComponent {
  constructor(@Inject(ErrorProneElementRef) readonly elementRef: ElementRef) { }
}

1
이것은 내가 겪고있는 문제를 설명합니다. item다른 ElementRef :로 설정하더라도 ElementRef 여야 하므로 작동하지 않습니다 let item:ElementRef, item2:ElementRef; item = item2; // no can do.. 매우 혼란 스럽습니다. 그러나 이것은 괜찮습니다 : let item:ElementRef, item2:ElementRef; item = item2.nativeElement구현으로 인해 지적했습니다.
oooyaya

1
실제로 첫 번째 예제 let item: ElementRef, item2: ElementRef; item = item2는 명확한 할당 분석으로 인해 실패합니다. 두 번째는 동일한 이유로 실패하지만 item2논의 된 이유로 초기화 된 경우 모두 성공합니다 (또는 declare let여기서 할당 가능성에 대한 유용한 빠른 검사로 ). 어쨌든, any이와 같은 공개 API 를 보는 것은 부끄러운 일 입니다.
Aluan Haddad

2

즉시 다음 형제를 얻으려면 이것을 사용하십시오.

event.source._elementRef.nativeElement.nextElementSibling

1

목록에서 대상 요소를 선택하십시오. 동일한 요소 목록에서 특정 요소를 쉽게 선택할 수 있습니다.

구성 요소 코드 :

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 코드 :

<ul *ngFor="let event of listEvents; let i = index">
   <li  (click)="selectElement(event.name, i)" [class]="event.class">
  {{ event.name }}
</li>

CSS 코드 :

.selected {
  color: red;
  background:blue;
}

0

빠른 사용법을위한 최소 예제 :

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

@Component({
  selector: 'my-app',
  template:
  `
  <input #inputEl value="hithere">
  `,
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  @ViewChild('inputEl') inputEl:ElementRef; 

  ngAfterViewInit() {
    console.log(this.inputEl);
  }
}
  1. 관심있는 DOM 요소에 템플릿 참조 변수를 넣습니다. 우리의 예에서 이것은이다 #inputEl<input>태그입니다.
  2. 컴포넌트 클래스에서 @ViewChild 데코레이터를 통해 DOM 요소를 주입하십시오.
  3. ngAfterViewInit수명주기 후크 의 요소에 액세스하십시오 .

노트 :

DOM 요소를 조작하려면 요소에 직접 액세스하는 대신 Renderer2 API를 사용하십시오. DOM에 직접 액세스를 허용하면 애플리케이션이 XSS 공격에 더 취약해질 수 있습니다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.