LoginSignup
17
9

More than 3 years have passed since last update.

AngularのngForでチャットコメントを実装する

Last updated at Posted at 2016-09-25

この記事はAngular+Firebaseでチャットアプリを作るのエントリーです。
前記事:Angularでビュー(チャット画面)を作る
次記事:AngularのngIfとsubmitイベントでチャットコメントを実装する

この記事で行うこと

本稿では、AngularのビルトインディレクティブであるngModel、ngForを使ってDOMを動的に操作していきます。

Angularのビルトインディレクティブ

Angularでは、AngularJS1.xxで使われていたビルトインディレクティブが、記法を変えて使用できるようになっています。

このビルトインディレクティブ、要はhtmlの中にJavaScriptのforやらifやらといった文法を取り入れてしまおうというもの。直感的にDOMの操作ができるようになるので便利です。
使い方はReactやVue.jsといった他のJavaScriptフレームワークと共通する部分も多いので、一度ビルトインディレクティブの使用方法を覚えれば、他のフレームワークでもDOM要素の中に条件文をいれる勘所がわかってくると思います。


(追記:2020/6)現時点(2020年6月)での最新の内容に書き換えています。


実装内容

ngModelによる双方向バインディング

AngularJS1.xxでもてはやされた双方向バインディングですが、Angularでも使うことができます。
実験的に、チャットのコメントフォームと出力されたコメントを連動させてみます。

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

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    NgbModule,
    FormsModule // 追加
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
src/app/app.component.ts
export class AppComponent {
  public content = '';
}
src/app/app.component.html
<div class="page">
  <section class="card">
    <div class="card-header">
      NgChat
    </div>
    <div class="card-body">
      <div class="media">
        <div class="media-left">
          <a href="#" class="icon-rounded">S</a>
        </div>
        <div class="media-body">
          <h4 class="media-heading">Suzuki Taro Date:2016/09/01</h4>
          <div>この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。</div>
        </div>
      </div>
      <hr>
      <div class="media">
        <div class="media-body">
          <h4 class="media-heading">Tanaka Jiro Date:2016/09/01</h4>
          <div>{{content}}</div><!--contentに変更-->
        </div>
        <div class="media-right">
          <a href="#" class="icon-rounded">T</a>
        </div>
      </div>
    </div>
  </section>

  <section>
    <form class="chart-form">
      <div class="input-group">
        <input type="text" class="form-control"
               [(ngModel)]="content"
               name="comment"
               placeholder="Comment" /><!--ngModel追加-->
        <div class="input-group-append">
          <button class="btn btn-info" type="button">SEND</button>
        </div>
      </div>
    </form>
  </section>
</div>

FormModuleの追加

[(ngModel)]はFormModuleに搭載されているディレィクティブで、使用する場合は@NgModuleでFormModuleをimportしておく必要があります。このように、Angularは最小単位の構成に対し、必要に応じて機能を追加していくスタイルをとっています。

実行結果

フォームの入力に合わせて、contentで紐付けたDOMがリアルタイムで変更されていきます。これがAngularの双方向バインディングです。
[(ngModel)]という書き方がきもいと某イベントで話題になっていました。公式のこのあたりの説明を見ると、単方向と双方向をわけるためにこの記述になったみたいです。

ezgif-1-8e71aa0ba3.gif

ngForでコメントを繰り返し表示させる

commentsオブジェクトを作る

さて、ngForを使うにあたりまずはcommentsオブジェクトをapp.component.tsに記述してみます。この時注意する点は、TypeScriptなので型の定義を忘れないことです。

src/app/app.component.ts
export class AppComponent {
  content = '';
  comments: { name: string, content: string }[] = [
    { name: 'Suzuki Taro',  content: '1つ目のコメントです。'},
    { name: 'Suzuki Taro',  content: '2つ目のコメントです。'},
    { name: 'Suzuki Taro',  content: '3つ目のコメントです。'}
  ];
}

型の定義はクラスファイルにまとめていきます。
interfaceでも型の定義は可能ですが、公式のスタイルガイドによるとinterfaceはなるべく使わず、クラスを使って定義していくことが推奨されています。

ng g class class/chat

作成されたchat.tsファイルにCommentクラスを作成します。

src/app/class/chat.ts
export class Comment {
  name: string;
  content: string;
}

commentsオブジェクトを定数としてAppComponentの外に出し、importしたCommentを型として使用します。

src/app/app.component.ts
import { Component } from '@angular/core';
import { Comment } from './class/chat'; // 追加

const COMMENTS: Comment[] = [ // 追加
  { name: "Suzuki Taro",  content: "1つ目のコメントです。"},
  { name: "Suzuki Taro",  content: "2つ目のコメントです。"},
  { name: "Suzuki Taro",  content: "3つ目のコメントです。"}
];

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent {
  public content = '';
  public comments = COMMENTS; // 追加
}

これでコンポーネント側の準備は整いました。

ngForをHTMLテンプレートに記述する

ここでようやくngForの登場です。
AngularJS1.xxを触ったことのある方なら、ng-repeatのAngularバージョンといった方がわかりやすいかもしれません。ng-repeat同様、AngularでもngForは多用されるディレクティブの1つです。

ngForulliタグで使われることが多いですが、階層構造がしっかりしていればdiv要素でも使用可能です。ngForが設置された階層より下にある階層のDOMを、指定された配列がなくなるまで繰り返します。

src/app/app.component.html
<div class="page">
  <section class="card">
    <div class="card-header">
      NgChat
    </div>
    <div class="card-body">
      <ng-container *ngFor="let comment of comments"><!--追加-->
      <div class="media">
        <div class="media-left">
          <a href="#" class="icon-rounded">S</a>
        </div>
        <div class="media-body">
          <h4 class="media-heading">{{comment.name}} Date:2016/09/01</h4><!--comment.nameに変更-->
          <div>{{comment.content}}</div><!--comment.contentに変更-->
        </div>
      </div>
      <hr>
      </ng-container>
      <div class="media">
        <div class="media-body">
          <h4 class="media-heading">Tanaka Jiro Date:2016/09/01</h4>
          <div>{{content}}</div><!--contentに変更-->
        </div>
        <div class="media-right">
          <a href="#" class="icon-rounded">T</a>
        </div>
      </div>
    </div>
  </section>

  <section>
    <form class="chart-form">
      <div class="input-group">
        <input type="text" class="form-control"
               [(ngModel)]="content"
               name="comment"
               placeholder="Comment" /><!--ngModel追加-->
        <div class="input-group-append">
          <button class="btn btn-info" type="button">SEND</button>
        </div>
      </div>
    </form>
  </section>
</div>

ng-containerディレクティブ

今回のngForにはng−containerディレクティブを使用しました。
このディレクティブは実行後のソースコードに表示されないため、意味のないタグ(div等)が表示されることを防ぐことができます。よりセマンティックなコードを実現したい場合に、このディレクティブを使用します。

実行結果

NgChat (1).png

登録したコメントが表示されました。
ただこれだとSuzukiさんばかりコメントしていてTanakaさんが可哀想なので、次はTanakaさんにもコメントしてもらいます。

ソースコード

この時点でのソースコード

17
9
1

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
17
9