2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

#Angularの公式チュートリアルを実践してみた。第2回目

Posted at

Angularの公式チュートリアルを実践してみた。第2回目

前回に引き続き公式チュートリアルを進めていきます。

前回は新しくコンポーネントを作りプロパティを設定、表示するといった
ことまで学びました。

クラスを作成する。

まず、src/appフォルダ内のに、新しくhero.tsファイルを作成します。
作成したらHeroクラスとidプロパティとnameプロパティを付与します。

src/app/hero.ts
export class Hero {
  id: number;
  name: string;
}

作成したクラスをhero.component.tsにインポートします。

src/app/heros.components.ts
import { Component, OnInit } from '@angular/core';
import { Hero } from '../hero';

@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
  hero: Hero = {
    id: 1,
    name: 'Windstorm'
  };

  constructor() { }

  ngOnInit() {
  }

}

Stringでバインディングされていたデータがオブジェクト型になったため、エラーが表示されるようになりました。

オブジェクトを表示する。

エラーを解消します。
解消するにはheros.component.htmlを編集し、バインディングを更新すればOKです。

heros.component.html
<h2>{{hero.name}} Details</h2>
<div><span>id: </span>{{hero.id}}</div>
<div><span>name: </span>{{hero.name}}</div>

ファイルが更新され、エラー表示が解消されます。

UppercasePipe で書式設定する。

このチュートリアルではcomponent.tsに設定されたnameをすべて大文字に設定して出力するといった感じ。
特筆事項がないので、飛ばします。

双方向データバインディング

次にユーザがinputボックスから新しいオブジェクトを編集できるようにします。
テキストボックスにはnameプロパティが表示され、ユーザの入力時にそのプロパティが更新されます。

流れとしてはこんな感じですね。

コンポーネント⇒画面表示⇒入力⇒コンポーネント

このデータフローを実現するために、inputフォームとhero.nameプロパティの間に双方向データバインディングを設定します。

以下のようにHeroesComponentテンプレートを編集します。

src/app/heroes/heroes.component.html
<h2>{{hero.name | uppercase}} Details</h2>
<div>
  <label>name:
    <input [(ngModel)]="hero.name" placeholder="name">
  </label>
</div>

(ここまでやってきて、Java EEにすごい似てるなと感じました。コンポーネントベースってやつですね。)

ちなみに、ここまでのサンプルを試すとブラウザ上では正常に表示されなくなります。
コンソールをデバッグツールで確認すると以下のようなエラーが出てるので確認します。(IEで確認してます。)

SCRIPT5022: SCRIPT5022: Template parse errors:
Can't bind to 'ngModel' since it isn't a known property of 'input'. ("
div>
  label>name:
    input [ERROR ->][(ngModel)]="hero.name" placeholder="name">
  /label>
/div>"): ng:///AppModule/HeroesComponent.html@3:11

さきほどHeroesComponentにngModelを追加しましたが
これはデフォルトで使用できないようです。

公式サイトには「これはオプションのFormsModuleに属しており、使用するにはそのモジュールをオプトインする必要があります。」
とあります。
要するに何かをインポートする必要があるみたいっすね。(適当)

AppModule

さて、どういうことか公式サイトをチェックしてみると

「一部のメタデータは、コンポーネントクラスに追加した@Componentデコレーター内にあります。」
「その他の重要なメタデータは@NgModuleデコレーター内にあります。」

要するに@Componetっていうデコレータと@NgModuleをが必要なんですね。

@NgModuleデコレーターは、トップレベルの AppModule クラスに注釈を付けます。Angular CLI は、プロジェクトを作成するときに
src/app/app.module.tsにAppModuleクラスを作成しました。」とあります。
では現時点でのapp.module.tsをチェックします。

src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HeroesComponent } from './heroes/heroes.component';

@NgModule({
  declarations: [
    AppComponent,
    HeroesComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }


ふむ、よくわからん。
AppModuleっていうクラスは定義されているみたいだけど?

FormsModule をインポートする

次に「AppModule (app.module.ts) を開き、@angular/formsライブラリからFormsModuleシンボルをインポートします。」
とあるので、インポート文を追加します。

また「それから、FormsModuleを@NgModuleメタデータのimports配列に追加します。
この配列には、アプリケーションに必要な外部モジュールのリストが含まれています。」とあるので、imports配列の追加とやらも
やります。

app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms'; // <-- NgModel lives here

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HeroesComponent } from './heroes/heroes.component';

@NgModule({
  declarations: [
    AppComponent,
    HeroesComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

ソースを保存すると自動でアプリケーションが再起動します。
inputボックスが出現してるので、そこの何か入力すると上にあるh2タグに反映されます。

コンポーネントを宣言する。

動作を確認したので、最後にルールの勉強です。
どうやらすべてのコンポーネントはNgModuleで宣言されている必要があるようです。

僕はNgModuleに宣言をしていないのになぜ動作したのか。
その答えはHeroesComponentを作成したときにAppModuleに自動生成されているためのようです。

app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms'; // <-- NgModel lives here

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HeroesComponent } from './heroes/heroes.component';

@NgModule({
  declarations: [
    AppComponent,
    HeroesComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

確かにimportが設定されていますね。
さらに「HeroesComponentは、@NgModule.declarations配列で宣言されています。」とあるように、declarationsに宣言がありますね。

ここまでが今回の内容になります。
コンポーネントのバインドに関する部分なので復習が必要になるかもしれませんが、ひとまずここまで!!!
今日の分もGitHubにpushしますのでよかったらご覧ください。

ではおやすみなさい~!

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?