Angularでビュー（チャット画面）を作る

> この記事は[Angular+Firebaseでチャットアプリを作る](http://qiita.com/Yamamoto0525/items/a76ea4b3924eeb82b0f9)のエントリーです。
> 前記事：[Angularの環境構築（Angular CLIで構築）](http://qiita.com/Yamamoto0525/items/65d5a0b36eb4dbd8079b)
> 次記事：[AngularのngForでチャットコメントを実装する](http://qiita.com/Yamamoto0525/items/5ee362967295ec4d2c65)

# この記事で行うこと

本稿では、Angularのテンプレートを更新し、ビュー（チャット用の画面）を作成します。

- [bootstrapをインストール](#bootstrapをインストール)
- [HTML、CSSを更新](#HTML、CSSを更新)

### Angularのビュー表示

Angular9.XXはAngularJS1.XXと同じく、ロジックにかかるファイル（js、 ts）とビューにかかるファイル（html、css）を分離して管理することができます。
これはReact、vue.jsと異なる点の１つです。

Reactに使われているJSXの文法はちょっと厄介なので、デザイナー（非エンジニア）に「JSXで納品して！」と言ってもかなり厳しいです。
なので、デザイナーから納品されたHTMLとCSSをJSXに書き換える、という作業を毎回エンジニアが行うことになり、仕事のスピード、正確性にかなり負荷がかかってきます。

その点、AngularはHTMLとCSSのみの静的なファイルを納品してもらってそのまま流し込むことができるので、エンジニアの負担軽減につながります。

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

# 実装内容

## bootstrapをインストール

ここ最近、新しくWEBアプリを構築しようとする時はなんらかのUIフレームワークをいれることがデファクトスタンダードになりつつあるんじゃないかと思っています。

GoogleのAngularを使うのだから、UIフレームワークもGoogleのマテリアルデザインを使おう！…と思ったのですが、2017年6月01日現在でまだ[angular-material2](https://github.com/angular/material2)は構築中のようでした。

***********
（追記：2018/9）現時点でほぼ運用可能なレベルまで開発が進んでいます。
***********

なので、とりあえずここはおなじみ(twitter)[bootstrap](https://getbootstrap.com/)のver4を入れておきます。

#### `ng add`コマンドを使ってインストールする場合

まずはangular6から追加された`ng add`コマンドを使って実装します。

```bash
ng add @ng-bootstrap/ng-bootstrap
```

>（追記：2020/6）angular9では以下エラーがは出ませんでした。
>（注）こちらを試したところ、次のようなエラーメッセージが出ました。
>
>```bash
>The package/collection may not support the 'targets' field within >'~/NgChat/angular.json'. 
>```
>`angular.json`ファイルの`targets`を`architect`に変更すると通りましたが、この挙動はバージョンによって異なると思いますので、表示されたエラーメッセージに従って対応してください。
>
>また、インストール後に`jquery@1.9.1 - 3 but none is installed.`のようなメッセージが表示されますが、bootstrapの動的な挙動を利用しない場合は無視して構いません


このコマンドによって、`app.module.ts`などの関連するファイルも自動的に更新されます。もし自動更新を避けたい場合は、下記の参考からバージョン管理を使ってインストール&ファイルの更新を行ってください。


## 参考

### Bootsrapのライブラリを直接インストールする場合

```bash
npm install bootstrap --save // ver4
npm install bootstrap@4.x.x --save // バージョンを指定

// SASS版
npm install bootstrap-scss --save
```

***********
（追記：2020/6）bootstrap-sassは開発がとまっているようなので、bootstrap-scssに変更しました
***********


#### コードを修正

`angular-cli.json`に`bootstrap.css`へのパスを追記します。

```json:angular-cli.json
  "styles": [
     "src/styles.css",
     {
       "input": "./node_modules/bootstrap/dist/css/bootstrap.css"
     }
  ],
```

`app.module.ts`に`bNgbModule`を追記します。

```ts:src/app/app.module.ts
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    NgbModule.forRoot() // 追加
  ],
  providers: [],
  bootstrap: [AppComponent]
})
```

### 動作確認

`app.component.html`の記述を変更し、UIに反映されているか確認します。

```html:src/app/app.component.html
<div class="content" role="main">

  <div class="mb-2">
    <button class="btn btn-primary">Test Button</button>
  </div>
```

```bash
ng serve
```

![screenshot-localhost_4200-2020.06.16-18_39_20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112566/931bb2ba-9bc5-63ac-3634-69a768bc38ff.png)


UIへの反映が確認できました。

## HTML、CSSを更新

### 指定されているテンプレートを確認

`app.component.ts`を見てみると、`@Component`にビューとなるテンプレートが指定されています。
ビューを更新する場合は、`@Component`でパスを確認します。

```ts:src/app/app.component.ts
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html', // HTMLを指定
  styleUrls: ['./app.component.css'] //CSSを指定
})
```

### コードを修正

ビューの元となっているHTMLとCSSを更新します。
デザイナーから静的ファイルが納品されることを想定し、JavaScriptにかかるものは全く実装されていないことを前提としておきます。

```html: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>この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。</div>
        </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" placeholder="Comment">
        <div class="input-group-append">
          <button class="btn btn-info" type="button">SEND</button>
        </div>
      </div>
    </form>
  </section>
</div>
```

```css:src/styles.css
html, body {
  height: 100%;
  font-family: "Hiragino Kaku Gothic ProN","メイリオ", sans-serif;
  font-size: 14px;
  line-height: 1.42857143;
  background-color: rgba(255, 251, 251, 0.78);
}
```

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

.page .card .media-body {
  padding: 18px;
  margin: 0 10px;
  background-color: #F5F5F5;
  border-radius: 10px;
  font-size: 15px;
  word-break: break-all;
}

.page .card .media-body h4.media-heading {
  color: #999999;
  font-size: 13px;
}

.page .card .card-block {
  padding: 10px;
}

.page .card a.icon-rounded {
  display: block;
  font-size: 28px;
  color: #fff;
  text-align: center;
  margin: 5px;
  padding: 5px;
  width: 50px;
  height: 50px;
  border-radius: 50%;
}

.page .card .media-left a.icon-rounded {
  background-color: #f0ad4e;
}

.page .card .media-right a.icon-rounded {
  background-color: #5cb85c;
}

.page .chart-form {
  margin: 20px 0;
}

```

### 実装後の画面

![view.png](https://qiita-image-store.s3.amazonaws.com/0/112566/5258c2c7-38aa-ec36-699d-1e7a1c9441d5.png)


## ソースコード

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