コンテンツへスキップ
Angularでの @Input() を使用したコンポーネント間の通信

Angularでの @Input() を使用したコンポーネント間の通信

この記事では、子コンポーネントが @Input() プロパティを使用して親コンポーネントと対話する方法に焦点を当てます。また、入力メッセージのインターセプトと、入力メッセージの変更のログ記録についても説明します。

8min read

Angularでは、コンポーネントはデータまたはイベントを渡すことで、データや情報を別のコンポーネントと共有できます。コンポーネントを別のコンポーネント内で使用できるため、コンポーネント階層を作成できます。別のコンポーネント内で使用されているコンポーネントは子コンポーネントと呼ばれ、外側のコンポーネントは親コンポーネントと呼ばれます。

Parent Child component relation

以下のリストで作成されたコンポーネントについて考えてみましょう。AppChildComponentというコンポーネントを作成し、別のコンポーネント内で使用します。

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

@Component({
  selector : 'appchild',
  template : `<h2> Hi{{greetMessage}} < / h2 >`
}) export class AppChildComponent {
  greetMessage : string = "I am Child";
}

また、AppComponentという別のコンポーネントも作成しました。AppComponent内では、AppChildComponentを使用しています。

import{Component} from '@angular/core';
import{AppChildComponent} from './appchild.component';

@Component({
  selector : 'my-app',
  template : `<h1> Hello{{message}} < / h1 > <br /><appchild></ appchild>
  `,
}) export class AppComponent {
  message : string = "I am Parent";
}

上記のリストでは、AppComonentはAppChildComponentを使用しているため、AppComponentは親コンポーネントであり、AppChildComponentは子コンポーネントです。

親コンポーネントから子コンポーネントへのデータの受け渡し

親コンポーネントから子コンポーネントにデータを渡すことから始めましょう。これは、input プロパティを使用して実行できます。@Inputデコレータまたは入力プロパティは、親コンポーネントから子コンポーネントにデータを渡すために使用されます。これを行うには、次のリストに示すように子AppChildComponentを変更する必要があります。

import{Component, Input, OnInit} from '@angular/core';

@Component({
  selector : 'appchild',
  template : `<h2> Hi{{greetMessage}} < / h2 >`
}) 

export class AppChildComponent implements OnInit {
  @Input() greetMessage : string;
  constructor() {}
  ngOnInit() {}
}

お気づきのように、greetMessage プロパティを @Input() デコレーターで変更しました。また、onInitを実装しており、後日デモで使用します。 したがって、基本的に、子コンポーネントでは、greetMessageプロパティを@Input()デコレータで装飾し、greetMessageプロパティの値を親コンポーネントから設定できるようにしました。

次に、親コンポーネント AppComponent を変更して、子コンポーネントにデータを渡しましょう。

import{Component} from '@angular/core';
import{AppChildComponent} from './appchild.component';

@Component({
  selector : 'my-app',
  template : `<h1> Hello{{message}} < / h1 > <br />
      <appchild[greetMessage] = "childmessage"></ appchild>
  `,
}) 
export class AppComponent {
  message : string = "I am Parent";
  childmessage : string = "I am passed from Parent to child component"
}

親コンポーネントから、子コンポーネントのプロパティ greetMessage の値を設定します。子コンポーネントに値を渡すには、子コンポーネントのプロパティを角括弧で囲み、その値を親コンポーネントの任意のプロパティに設定する必要があります。childmessage プロパティの値を親コンポーネントから子コンポーネントの greetMessage プロパティに渡しています。

ChildMessage プロパティの値を親コンポーネントから greetMessage プロパティに渡す

子コンポーネントの親コンポーネントからの入力をインターセプトする

親コンポーネントから渡されたデータを子コンポーネント内でインターセプトする必要がある場合があります。これは、入力プロパティのgettersetterを使用して実行できます。

子コンポーネントで受信メッセージをインターセプトし、それを文字列と組み合わせたいとします。 これを実現するために、_greetmessage というプロパティを作成し、@Input() デコレーターを使用して _greetmessage プロパティの getter と setter を作成しました。ゲッターでは、親コンポーネントからの入力をインターセプトし、それを文字列と組み合わせています。これは、次のリストに示すように実行できます。

import{Component, Input, OnInit} from '@angular/core';

@Component({
  selector : 'appchild',
  template : `<h2> Hi{{_greetMessage}} < / h2 >`
}) 

export class AppChildComponent implements OnInit {
  _greetMessage : string;
  constructor() {}
  ngOnInit() {}

  @Input() set greetMessage(message : string) {
    this._greetMessage = message + " manipulated at child component";
  }
  get greetmessage() { return this._greetMessage; }
}

セッターでは、親コンポーネントからの受信データを操作し、それにテキストを追加します。メッセージをインターセプトしているかどうかに関係なく、親コンポーネントの動作は変更されないことに注意してください。さらに詳しく調べるために、別の例を取り上げて、親から渡された名前を表示する子コンポーネントを作成しましょう。親が空の名前値を渡すと、子コンポーネントにはデフォルトの名前が表示されます。これを行うために、子コンポーネントのセッターを変更しました。セッターでは、名前の値が渡されるかどうかをチェックしています。渡されない場合、または空の文字列の場合、name の値はデフォルト値に割り当てられます。子コンポーネントは、次のリストに示すように作成できます。

import{Component, Input, OnInit} from '@angular/core';

@Component({
  selector : 'appchild',
  template : `<h2>{{_name}} < / h2 >`
}) 

export class AppChildComponent implements OnInit {
  _name : string;
  constructor() {}
  ngOnInit() {}

  @Input() set Name(name : string) {
    this._name = (name && name.trim()) || "I am default name";
  }
  get Name() { return this._name; }
}

@Input()セッターでお気づきのように、親から渡された値をインターセプトし、それが空の文字列であるかどうかをチェックしています。空の文字列の場合は、子コンポーネントの名前にデフォルト値を割り当てます。

以下のリストに示すように、親コンポーネント AppComponent 内で AppChildComponent を使用できます。

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

@Component({
  selector : 'my-app',
  template : `<h1> Hello{{message}} < / h1 > <br />

      <appchild *ngFor = "let n of childNameArray"[Name] = "n"></ appchild>
  `,
}) 
export class AppComponent {
  message : string = "I am Parent";
  childmessage
      : string = "I am passed from Parent to child component" childNameArray =
            [ 'foo', 'koo', ' ', 'moo', 'too', 'hoo',''];
}

親コンポーネント内では、childNameArrayプロパティのすべての項目を介して子コンポーネントをループしています。childNameArrayのいくつかの項目は空の文字列であり、これらの空の文字列は子コンポーネントセッターによってインターセプトされ、デフォルト値に設定されます。子コンポーネントは、次の画像に示すように、親コンポーネントから渡された値をレンダリングします。

子コンポーネントは、親コンポーネントから渡された値をレンダリングします

ngOnChanges と @Input() デコレータ

コンポーネントのOnChangesライフサイクルフックを使用して、入力プロパティの変更をインターセプトできます。Input プロパティが親コンポーネントで変更され、子コンポーネントでインターセプトする必要がある理由はさまざまです。これは、OnChanges ライフサイクル フックで実行できます。

counterと呼ばれるInput変数の変更をログに記録する必要があると想像してみましょう。カウンタの値は親コンポーネントによって設定され、親コンポーネントで変更できます。親コンポーネントでカウンタの値が変更されるたびに、子コンポーネントの変更をログに記録する必要があります。以下のリストに示すように、子コンポーネントを作成しました。

import{Component, Input, OnChanges, SimpleChange} from '@angular/core';

@Component({
  selector : 'appchild',
  template : `<h2>{{counter}} < / h2 > <h2> Value Changed</ h2><ul>
      <li *ngFor = "let c of changeLog">{{c}} < / li >
      </ ul> 
    `
}) 

export class AppChildComponent implements OnChanges {
  @Input() counter = 0;
  changeLog : string[] = [];
  constructor() {}

  ngOnChanges(changes : {[propKey:string] : SimpleChange}) {
    let log : string[] = [];
    for (let p in changes) {
      let c = changes[p];
      console.log(c);
      let from = JSON.stringify(c.previousValue);
      let to = JSON.stringify(c.currentValue);
      log.push(`${p} changed from ${from} to $ { to }`);
    }

    this.changeLog.push(log.join(', '));
  }
}

基本的に、私たちは次のことを行っています。

  1. OnChanges ライフサイクルフックの実装
  2. ngOnChangesメソッドで、SimpleChange型の配列を渡します
  3. すべての変更を反復処理し、それを文字列配列にプッシュする

counter の値が変更されるたびに、子コンポーネントは以前の値と現在の値をログに記録します。各入力プロパティの以前の値と現在の値の読み取りは、下の画像に示すようにngOnChnagesメソッドで行われます。

各入力プロパティの以前の値と現在の値の読み取りは、次のようにngOnChnagesメソッドで行われます

親コンポーネントでは、ボタンのクリック時にプロパティをカウントするための新しい乱数を割り当て、countプロパティを子コンポーネントの入力プロパティカウンタの値として設定しています。

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

@Component({
  selector : 'my-app',
  template : `<h1> Hello{{message}} < / h1 >
      <br /><button(click) = "nextCount()"> change count</ button><br />
      <appchild[counter] = "count"></ appchild> 
  `,
}) 

export class AppComponent {
  count : number = 0;

  nextCount() {
    console.log("hahahah");
    this.count = this.getRandomIntInclusive(this.count, this.count + 1000);
  }

  getRandomIntInclusive(min : number, max : number) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min;
  }
}

基本的に親コンポーネントでは、子コンポーネントの入力プロパティカウンタの値を親コンポーネントのcountプロパティで設定し、ボタンをクリックするたびにその値を変更します。 親コンポーネントでcountプロパティ値が変更されるたびに、子コンポーネントでcounter入力プロパティの値が変更され、変更された値がログに記録されます。

アプリケーションを実行すると、下の画像に示すように、変更ログを含む期待される出力が得られる場合があります。

アプリケーションを実行すると、変更ログで期待される出力が得られる場合があります

結論

この記事では、親コンポーネントから子コンポーネントにデータを渡す方法を学びました。また、入力メッセージをインターセプトして変更をログに記録する方法も学習しました。今後の投稿では、コンポーネント通信のさらなる側面について説明します。この投稿がお役に立てば幸いです、読んでくれてありがとう。

デモを予約