AngularのngIfとsubmitイベントでチャットコメントを実装する

> この記事は[Angular+Firebaseでチャットアプリを作る](http://qiita.com/Yamamoto0525/items/a76ea4b3924eeb82b0f9)のエントリーです。
> 前記事：[AngularのngForでチャットコメントを実装する](http://qiita.com/Yamamoto0525/items/5ee362967295ec4d2c65)
> 次記事：[AngularのPipeを使って、日付を変換する](http://qiita.com/Yamamoto0525/items/afc1c23ea56ae20a1931)

# この記事で行うこと

本稿では、AngularのビルトインディレクティブであるngIfとsubmitイベントを使って、前回に引き続きDOMを操作していきます。

- [ngIfで自分のコメントを表示させる](http://qiita.com/Yamamoto0525/items/a6995da3ffbb4985c5e2#ngif%E3%81%A7%E8%87%AA%E5%88%86%E3%81%AE%E3%82%B3%E3%83%A1%E3%83%B3%E3%83%88%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%95%E3%81%9B%E3%82%8B)
- [submitイベントで新しいコメントを追加する](http://qiita.com/Yamamoto0525/items/a6995da3ffbb4985c5e2#click%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%A7%E6%96%B0%E3%81%97%E3%81%84%E3%82%B3%E3%83%A1%E3%83%B3%E3%83%88%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B)

*****
（追記：2020/6）現時点（2020年6月）での最新の内容に書き換えています。
*****


# 実装内容

## ngIfで自分のコメントを表示させる

###  自分と自分以外を判別するフラグをつける

前回、定数として作成したCOMMENTSに、userとinitialというプロパティを追加し、自分のユーザー情報を作成します。
それに合わせて、定義ファイルchat.tsも更新します。

```ts:src/app/class/chat.ts
export class User { // Userの定義を追加
  uid: number;
  name: string;

  constructor(uid: number, name: string) {
    this.uid = uid;
    this.name = name;
  }
}

export class Comment { // Commentの定義を変更
  user: User;
  initial: string;
  content: string;

  constructor(user: User, content: string) {
    this.user = user;
    this.initial = user.name.slice(0, 1);
    this.content = content;
  }
}
```

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


const CURRENT_USER: User = new User(1, 'Tanaka Jiro'); // 自分のUser情報を追加
const ANOTHER_USER: User = new User(2, 'Suzuki Taro'); // 相手のUser情報を追加
const COMMENTS: Comment[] = [ // クラスを元にコメントを作成
  new Comment(ANOTHER_USER, 'Suzukiの１つ目のコメントです。'),
  new Comment(ANOTHER_USER, 'Suzukiの2つ目のコメントです。'),
  new Comment(CURRENT_USER, 'Tanakaの１つ目のコメントです。'),
  new Comment(ANOTHER_USER, 'Suzukiの3つ目のコメントです。'),
  new Comment(CURRENT_USER, 'Tanakaの2つ目のコメントです。')
];

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  public content = '';
  public comments = COMMENTS;
  public currentUser = CURRENT_USER; // 追加
}
```

###  `ngIf`で自分のuidを判別し、自分のコメントとして表示させる

`ngIf`は、条件式の値が`ture`の時にDOMを表示させるビルトインディレクティブです。
commentのuidとCURRENT_USERのuidを比較して、値が等しい時は右側に自分のアイコンが出るよう設定します。

```html: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">
        <!--current_user.uidとcomment.user.uidが等しくない場合に表示-->
        <div class="media-left" *ngIf="comment.user.uid !== currentUser.uid">
          <a href="#" class="icon-rounded">{{comment.initial}}</a>
        </div>
        <div class="media-body">
          <h4 class="media-heading">{{comment.user.name}} Date:2016/09/01</h4>
          <div>{{comment.content}}</div>
        </div>
        <!--current_user.uidとcomment.user.uidが等しい場合に表示-->
        <div class="media-right" *ngIf="comment.user.uid === currentUser.uid">
          <a href="#" class="icon-rounded">{{comment.initial}}</a>
        </div>
      </div>
      <hr>
      </ng-container>
    </div>
  </section>

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

DOMが長くなったことで表示の一部が崩れたので、CSSを修正します。

```css:src/app/app.component.css
.page { /*更新*/
  max-width: 960px;
  height: 100%;
  margin: 0 auto;
  padding: 10px 0;
  background-color: #fff;
  border-left: 1px solid #DDDDDD;
  border-right: 1px solid #DDDDDD;
  box-shadow: 0 0 15px #DDDDDD;
  overflow: scroll;
}

.page section{ /*追加*/
  margin: 0 10px 30px;
}

.page .page-footer{ /*追加*/
  display: block;
  position: fixed;
  margin: 0;
  padding: 10px;
  bottom: 0;
  height: 55px;
  width: 100%;
  max-width: 958px;
  background-color: #fff;
  border-top: 1px solid #DDDDDD;
}

/*削除
.page .chart-form {
  margin: 20px 0;
}*/
 
```
>#### ディレクティブの`*`と括弧`[]``()`
>`*ngIf`のように、ディレクティブの前に`*`がついた場合、その＝の先にある式はscript文として評価されます。例：`*ngIf="comment.user.uid !== current_user.uid"`の場合、それぞれのuidが等しい場合にのみ表示される。
>一方、同様に他のディレクティブ　内でもscript文として変数や式を利用したい場合は、`[]`や`()`を使って表現します。例：`[style.color]="comment.user.uid !== current_user.uid ? 'red' : 'black'"`の場合、それぞれのuidが等しい場合にのみ文字色が赤くなる。

## submitイベントで新しいコメントを追加する

### `addComment`関数を`AppComponent`に追加する

フォームに入力したコメントをチャットに追加するため、`addComment`関数を実装します。

```ts:src/app/app.component.ts
export class AppComponent {
  public content = '';
  public comments = COMMENTS;
  public current_user = CURRENT_USER;

  // 新しいコメントを追加
  addComment(comment: string) {
     if (comment) {
       this.comments.push(new Comment(this.current_user, comment));
     }
  }
```

### submitイベントをHTMLに追加する

Angularは、ビューからデータへ値を渡す時、`(click)`や`(submit)`のように丸括弧`()`をつけて表記します。
（この表記はビューからデータへ、一方向だけに送られるということを意味しています。逆にデータをビューへ渡す時は、角括弧`[ ]`を使って表記します。）

`ngModel`でcontentを紐付け、入力された値をaddComment関数に渡します。

```html:src/app/app.component.html
  <section>
    <form class="chart-form" (submit)="addComment(content)"><!--addComment()を追加-->
      <div class="input-group">
        <input type="text" class="form-control"
               [(ngModel)]="content"
               name="comment"
               placeholder="Comment" />
        <div class="input-group-append">
          <button class="btn btn-info" type="submit">SEND</button><!--submitに変更-->
        </div>
      </div>
    </form>
  </section>
```

### 実行結果

フォームに「コメント　テスト」と入力して、SENDボタンをクリックすると、チャットコメントが追加されました。

![ezgif-1-e20e8462e8.gif](https://qiita-image-store.s3.amazonaws.com/0/112566/928848fa-2b1f-070d-690f-e248dfb8aac9.gif)

## ソースコード

この時点での[ソースコード](https://github.com/Yamamoto0525/NgChat/commit/1288f4f3e9690bc51bb07b360cf398b5fa931930)