web-dev-qa-db-ja.com

コンポーネントテンプレートの要素を選択する方法

コンポーネントテンプレートで定義された要素を取得する方法を誰かが知っていますか? Polymerは$$$でそれを本当に簡単にします。

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要素の参照を取得する方法を教えてください。

408
Aman Gupta

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;

変更を購読する

Viewの子はngAfterViewInit()が呼び出されたときにのみ設定され、contentの子は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);
  }
}

任意の投影コンテンツを取得する

変換されたコンテンツへのアクセス を参照してください。

769

コンポーネントのコンストラクタにインジェクトすることで、ElementRefを介してDOM要素へのハンドルを取得できます。

constructor(myElement: ElementRef) { ... }

ドキュメント: https://angular.io/docs/ts/latest/api/core/index/ElementRef-class.html

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

最新バージョンで動作するように更新された例

ネイティブ要素の詳細については、 here

46
gdi2290

Angular 4 +:CSSセレクターでrenderer.selectRootElementを使用して要素にアクセスします。

最初に電子メール入力を表示するフォームがあります。電子メールが入力されると、フォームが展開され、プロジェクトに関連する情報を引き続き追加できるようになります。ただし、それらが既存のクライアントではないnotの場合、フォームにはプロジェクト情報セクションの上に住所セクションが含まれます。

現在、データ入力部分はコンポーネントに分割されていないため、セクションは* ngIfディレクティブで管理されます。既存のクライアントの場合はプロジェクトノートフィールドにフォーカスを設定し、新規の場合は名フィールドにフォーカスを設定する必要があります。

私は成功せずに解決策を試しました。ただし、 this answerのUpdate 3は、最終的な解決策の半分を提供しました。他の半分は this スレッドでの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');
    }
}

私がしているのは要素にフォーカスを設定することだけなので、変更の検出について心配する必要はありません。そのため、Angularの外部でrenderer.selectRootElementの呼び出しを実際に実行できます。新しいセクションをレンダリングする時間を与える必要があるため、要素の選択が試行される前にレンダリングスレッドが追いつくために、要素セクションはタイムアウトでラップされます。すべての設定が完了したら、基本的なCSSセレクターを使用して単純に要素を呼び出すことができます。

この例では主にフォーカスイベントを扱ったことを知っていますが、他のコンテキストでこれを使用できないのは私にとって難しいことです。

18
Neil T.

*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 { ... }

このテンプレートを使用してElementRef AND 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
jsgoupil
 */
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

次のように、@ angular/coreからViewChildデコレータをインポートします。

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



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

    class TemplateFormComponent {

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

これで、 'myForm'オブジェクトを使用して、クラス内のその中の任意の要素にアクセスできます。

ソース: https://codecraft.tv/courses/angular/forms/template-driven/ /

8
Hany

私はあなたが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) { }
}
3
Aluan Haddad

すぐ次の兄弟を取得するには、これを使います

event.source._elementRef.nativeElement.nextElementSibling
1
Apoorv

リストからターゲット要素を選択します。同じ要素のリストから特定の要素を選択するのは簡単です。

コンポーネントコード:

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