このサイトは、只今WEB業界で活躍中のデザイナー、プログラマーの方々の情報を集めたweb統合情報サイトです。

web帳

記事詳細

2017.04.03

Angular2の始め方。Angular2 公式チュートリアル – Multiple Components(簡単な和訳)

MULTIPLE COMPONENTS

こちらのページは、こちらのページの簡単な和訳です。

Angular2 tutorial | MULTIPLE COMPONENTS

前回

Angular2の始め方。Angular2 公式チュートリアル – Master/Detail(簡単な和訳)

その他

Angular2の始め方。Angular2 公式チュートリアル – SETUP FOR LOCAL DEVELOPMENT(簡単な和訳)Angular2の始め方。Angular2 公式チュートリアル – Introduction(簡単な和訳)
Angular2の始め方。Angular2 公式チュートリアル – The Hero Editor(簡単な和訳)

私たちのアプリは成長してきています。

コンポーネントを再利用し、データをコンポーネントに渡し、より再利用可能なリソースを作成するためのユースケースがでてきております。

ヒーローのリストをヒーローの詳細から分離して、詳細コンポーネントを再利用可能にしましょう。

Run the live example for this part.

Where We Left Off

ヒーローのツアーを続ける前に、次の構造を持っていることを確認しましょう。そうでない場合は、前の章に戻って行ってください。

angular-tour-of-heroes
├──src
│ ├──app
│ │  ├──app.component.ts
│ │  └──app.module.ts
│ ├──main.ts
│ ├──index.html
│ ├──styles.css
│ ├──systemjs.config.js
│ └──tsconfig.json
├──node_modules ...
└──package.json

Make a hero detail component

hero-detail.component.tsという名前のファイルを app /フォルダーに追加します。

このファイルは新しいHeroDetailComponentを保持します。

ファイル名とコンポーネント名は、スタイルガイドに記載されている標準に従います。

コンポーネントクラス名は、キャメルケースの大文字で書かれ、 “Component”という単語で終わるべきです。

主人公の詳細コンポーネントクラスはHeroDetailComponentです。

コンポーネントファイルの名前は、ダッシュ記号で綴る必要があります。各単語はダッシュで区切り、.component.tsで終わります。

HeroDetailComponentクラスはhero-detail.component.tsファイルに入れられます。

次のようにHeroDetailComponentの書き込みを開始します。

app/hero-detail.component.ts (initial version)

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

@Component({
  selector: 'hero-detail',
})
export class HeroDetailComponent {
}

コンポーネントを定義するには、常にコンポーネントシンボルをインポートします。

@Componentデコレータは、コンポーネントのメタデータを提供します。 CSSセレクタ名、hero-detailは、親コンポーネントのテンプレート内このコンポーネントを特定する要素タグにマッチします。このチュートリアルページの終わり近くに、あなたはAppComponentテンプレートに要素を追加します。

常に他の場所にimportするため、コンポーネントクラスをexportしてください。

Hero detail template

ヒーロー詳細ビューを HeroDetailComponentに移動するには、ヒーロー詳細コンテンツをAppComponentテンプレートの下部から切り取り、@Componentメタデータの新しいテンプレートプロパティに貼り付けます。

HeroDetailComponentには、選択されたヒーローではなく、ヒーローがあります。 “selectedHero”という単語をテンプレートのどこにでも置いて “hero”という単語に置き換えます。完了したら、新しいテンプレートは次のようになります。

src/app/hero-detail.component.ts (template)

@Component({
  selector: 'hero-detail',
  template: `
    <div *ngIf="hero">
      <h2>{{hero.name}} details!</h2>
      <div><label>id: </label>{{hero.id}}</div>
      <div>
        <label>name: </label>
        <input [(ngModel)]="hero.name" placeholder="name"/>
      </div>
    </div>
  `
})
Add the hero property

HeroDetailComponentテンプレートは、コンポーネントのheroプロパティにバインドされます。

そのようなプロパティをHeroDetailComponentクラスに次のように追加します。

src/app/hero-detail.component.ts (hero property)

hero: Hero;

ヒーロープロパティはヒーローのインスタンスとしてタイプされます。 Heroクラスはまだapp.component.tsファイルにあります。
今、Heroクラスを参照する必要がある2つのコンポーネントがあります。

Angularスタイルガイドでは、ファイルごとに1つのクラスを推奨します。

Heroクラスをapp.component.tsから独自のhero.tsファイルに移動します。

src/app/hero.ts

export class Hero {
  id: number;
  name: string;
}

Heroクラスが独自のファイルになったので、AppComponentと、HeroDetailComponentはそれをインポートする必要があります。

app.component.tsファイルと、hero-detail.component.tsファイルの上部に次のimport文を追加します。

import { Hero } from './hero';
The hero property is an input property

このページの後半では、親AppComponentは、選択されたヒーローをHeroDetailComponentのヒーロープロパティにバインドして表示するヒーローを子供のHeroDetailComponentに伝えます。バインディングは次のようになります。

<hero-detail [hero]="selectedHero"></hero-detail>

ヒーロープロパティの周りに等号(=)の左側に角括弧を置くと、プロパティバインディング式のターゲットになります。

ターゲットバインディングプロパティを入力プロパティに宣言する必要があります。

それ以外の場合、Angularはバインディングを拒否し、エラーをスローします。

まず、入力シンボルを含めるために @angular/core のimport文を修正します。

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

その後、ヒーローは、前にインポートした@Inputデコレータを前に置いて、入力プロパティであることを宣言します。

src/app/hero-detail.component.ts (excerpt)

@Input() hero: Hero;

““
属性の詳細については、属性ディレクティブのページを参照してください。

““

これで終了となります。ヒーロープロパティはHeroDetailComponentクラスの唯一のものです。

export class HeroDetailComponent {
  @Input() hero: Hero;
}

それが行うことは、ヒーロー入力プロパティでヒーローオブジェクトを受け取った後、そのテンプレートでそのプロパティにバインドすることだけです。

ここには完全なHeroDetailComponentがあります。

src/app/hero-detail.component.ts

import { Component, Input } from '@angular/core';
import { Hero } from './hero';
@Component({
  selector: 'hero-detail',
  template: `
    <div *ngIf="hero">
      <h2>{{hero.name}} details!</h2>
      <div><label>id: </label>{{hero.id}}</div>
      <div>
        <label>name: </label>
        <input [(ngModel)]="hero.name" placeholder="name"/>
      </div>
    </div>
  `
})
export class HeroDetailComponent {
  @Input() hero: Hero;
}

Declare HeroDetailComponent in the AppModule

すべてのコンポーネントは、1つの唯一のAngularモジュールで宣言する必要があります。

エディタでapp.module.tsを開き、参照できるようにHeroDetailComponentをインポートします。

src/app/app.module.ts

import { HeroDetailComponent } from './hero-detail.component';

HeroDetailComponentをモジュールの宣言配列に追加します。

src/app/app.module.ts

declarations: [
  AppComponent,
  HeroDetailComponent
],

一般に、宣言配列には、モジュールに属するアプリケーションコンポーネント、パイプ、およびディレクティブのリストが含まれています。

他のコンポーネントがモジュールを参照するには、そのモジュール内でコンポーネントを宣言する必要があります。

このモジュールは、AppComponentと、HeroDetailComponentの2つのアプリケーションコンポーネントのみを宣言します。

““`

NgModulesガイドのAngularモジュールの詳細
““`

Add the HeroDetailComponent to the AppComponent

AppComponentはまだ master/detail ビューです。

それはテンプレートのその部分を切り取る前に、ヒーローの詳細を独自に表示することでした。

今度はHeroDetailComponentに委譲します。

hero-detailは、HeroDetailComponentメタデータのCSSセレクタであることを思い出してください。

これは、HeroDetailComponentを表す要素のタグ名です。

ヒーロー詳細ビューを使用していた、AppComponentテンプレートの下部に

要素を追加します。

AppComponentのselectedHeroプロパティを、 HeroDetailComponentのヒーロープロパティにバインドして、マスターAppComponentをHeroDetailComponentと調整します。

app.component.html (excerpt)

<hero-detail [hero]="selectedHero"></hero-detail>

selectedHeroが変更されるたびに、HeroDetailComponentは新しいヒーローを取得して表示します。

修正されたAppComponentテンプレートは、次のようになります。

app.component.ts (excerpt)

template: `
  <h1>{{title}}</h1>
  <h2>My Heroes</h2>
  <ul class="heroes">
    <li *ngFor="let hero of heroes"
      [class.selected]="hero === selectedHero"
      (click)="onSelect(hero)">
      <span class="badge">{{hero.id}}</span> {{hero.name}}
    </li>
  </ul>
  <hero-detail [hero]="selectedHero"></hero-detail>
`,

What changed?

以前のように、ユーザーがヒーロー名をクリックするたびに、ヒーローの詳細がヒーローリストの下に表示されます。

しかし、今、HeroDetailViewはそれらの詳細を提示しています。

元のAppComponentを2つのコンポーネントにリファクタリングすることで、現状も今後にも利益がでます。

・AppComponentの責任を軽減してAppComponentを単純化しました。

・親AppComponentに触れることなく、HeroDetailComponentを豊かなヒーローエディタに拡張させることができます。

・ヒーロー詳細ビューに触れることなくAppComponentを拡張させることができます。

・将来の親コンポーネントのテンプレートでHeroDetailComponentを再利用することができます。

Review the app structure

次の構造を持っていることを確認します。

angular-tour-of-heroes
├──src
│ ├──app
│ │  ├──app.component.ts
│ │  ├──app.module.ts
│ │  ├──hero.ts
│ │  └──hero-detail.component.ts
│ ├──main.ts
│ ├──index.html
│ ├──styles.css
│ ├──systemjs.config.js
│ └──tsconfig.json
├──node_modules ...
└──package.json

このページで解説するコードファイルは次のとおりです。

src/app/hero-detail.component.ts

import { Component, Input } from '@angular/core';
import { Hero } from './hero';
@Component({
  selector: 'hero-detail',
  template: `
    <div *ngIf="hero">
      <h2>{{hero.name}} details!</h2>
      <div><label>id: </label>{{hero.id}}</div>
      <div>
        <label>name: </label>
        <input [(ngModel)]="hero.name" placeholder="name"/>
      </div>
    </div>
  `
})
export class HeroDetailComponent {
  @Input() hero: Hero;
}

src/app/app.component.ts

import { Component } from '@angular/core';
import { Hero } from './hero';
const HEROES: Hero[] = [
  { id: 11, name: 'Mr. Nice' },
  { id: 12, name: 'Narco' },
  { id: 13, name: 'Bombasto' },
  { id: 14, name: 'Celeritas' },
  { id: 15, name: 'Magneta' },
  { id: 16, name: 'RubberMan' },
  { id: 17, name: 'Dynama' },
  { id: 18, name: 'Dr IQ' },
  { id: 19, name: 'Magma' },
  { id: 20, name: 'Tornado' }
];
@Component({
  selector: 'my-app',
  template: `
    <h1>{{title}}</h1>
    <h2>My Heroes</h2>
    <ul class="heroes">
      <li *ngFor="let hero of heroes"
        [class.selected]="hero === selectedHero"
        (click)="onSelect(hero)">
        <span class="badge">{{hero.id}}</span> {{hero.name}}
      </li>
    </ul>
    <hero-detail [hero]="selectedHero"></hero-detail>
  `,
  styles: [`
    .selected {
      background-color: #CFD8DC !important;
      color: white;
    }
    .heroes {
      margin: 0 0 2em 0;
      list-style-type: none;
      padding: 0;
      width: 15em;
    }
    .heroes li {
      cursor: pointer;
      position: relative;
      left: 0;
      background-color: #EEE;
      margin: .5em;
      padding: .3em 0;
      height: 1.6em;
      border-radius: 4px;
    }
    .heroes li.selected:hover {
      background-color: #BBD8DC !important;
      color: white;
    }
    .heroes li:hover {
      color: #607D8B;
      background-color: #DDD;
      left: .1em;
    }
    .heroes .text {
      position: relative;
      top: -3px;
    }
    .heroes .badge {
      display: inline-block;
      font-size: small;
      color: white;
      padding: 0.8em 0.7em 0 0.7em;
      background-color: #607D8B;
      line-height: 1em;
      position: relative;
      left: -1px;
      top: -4px;
      height: 1.8em;
      margin-right: .8em;
      border-radius: 4px 0 0 4px;
    }
  `]
})
export class AppComponent {
  title = 'Tour of Heroes';
  heroes = HEROES;
  selectedHero: Hero;
  onSelect(hero: Hero): void {
    this.selectedHero = hero;
  }
}

src/app/hero.ts

export class Hero {
  id: number;
  name: string;
}

app.module.ts

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule }   from '@angular/forms';
import { AppComponent }        from './app.component';
import { HeroDetailComponent } from './hero-detail.component';
@NgModule({
  imports: [
    BrowserModule,
    FormsModule
  ],
  declarations: [
    AppComponent,
    HeroDetailComponent
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule { }

The road you’ve travelled

このページであなたが達成したことは次のとおりです。

・再利用可能なコンポーネントを作成しました。

・コンポーネントが入力を受け入れる方法を学びました。

・必要なアプリケーション指令をAngularモジュールで宣言することを学びました。

・NgModuleデコレータの宣言配列にディレクティブをリストしました。

・親コンポーネントを子コンポーネントにバインドする方法を学びました。

・あなたのアプリはこのlive example / downloadable example.のように見えるはずです。

The road ahead

Tour of Heroesアプリは、共有コンポーネントで再利用可能ですが、そのモックデータはまだAppComponent内でハードコーディングされています。

それは持続可能ではありません。

データアクセスは別のサービスにリファクタリングし、データを必要とするコンポーネント間で共有する必要があります。

次のチュートリアルページでサービスを作成する方法を学びます。

Next Step

Angular2の始め方。Angular2 公式チュートリアル – Services(簡単な和訳)

  • RSSを登録する

  • follow us in feedly

Graphical FrontEnd Engineer
- Daisuke Takayama

MAD CITY 北九州市で生まれ育つ。20代はバンド活動に明け暮れ、ふと「webデザイナーになりたい。」と思い、デジタルハリウッド福岡校入学。卒業後、数々の賞を受賞、web業界をざわつかせる。
現在、港区六本木で活動中。

WEBデザイナーの、WEBデザイナーによる、WEBデザイナーの為のサイト。「みんなで書こう!」と仲間を募ってみたが、結局書くのは自分だけとなってしまいました。日々のメモを綴っていきます。