JavaScript超初心者向け Meteor メモ (3) シンプルなチャットを作ってみる 

# 今回はチュートリアルに挑戦！w

[Meteor.js](https://www.meteor.com/)は、 **Webアプリづくりを楽しくする** フレームワークです。

<a href="https://www.meteor.com/"><img src="http://img.dfm.lrv.jp/meteor1/meteorlogo.jpg"></a>

前回はv0.8.0での変更点を見てみましたが差分情報ばかりで、あまり「超初心者向け」になってませんでしたね。すいません。
やはり、作りながら覚えないと面白くない！
というわけで、今回は、動くものを作りながらテンプレートやデータベース（コレクション）の使い方を覚えちゃいましょう！という企画です。

## つくるもの：シンプルなチャット

今回は、チャットを作ってみましょう。

[こんなの(ライブデモ)](http://tadfmac-simpleboard.meteor.com/)です。
<a href="http://tadfmac-simpleboard.meteor.com/"><img src="http://img.dfm.lrv.jp/meteor3/sc1.png"></a>

こんな感じのものです。

- チャットなのでリロード無しに相手が書き込んだときに自動的に自分が開いているブラウザの表示に反映される。
- ログイン機能などは無し。部屋のような機能もありません。誰でも書けます。
- テキストボックスでenterキーを押したら入力を確定させます。
- 見やすいように色分けする機能つき
- 10件まで表示。古いのは自動的に消えます。

このように、シンプルな機能のチャットではありますが、リアクティブでリアルタイムに同期するMeteorならでわの動きを体感することができると思います。
今度こそ、 **Meteorを始めてインストールするぞ！** という方も、是非一緒に進めてみてください！

# 準備

それでは、はじめましょう！

## すいません。。。MacかLinuxで

いきなりごめんなさい、なのですが、MeteorはまだWindowsに対応してません。。。
是非、MacかLinuxを準備してください。

## Meteorのインストール

まず、Meteorをインストールしましょう。

  >  $ curl https://install.meteor.com/ | sh

これでインストール完了です。
※万が一うまくいかない方は、[JavaScript超初心者向け Meteor メモ (1)](http://qiita.com/tadfmac/items/a63bb85e5cfb12bbbfc8)も参照してみてください。

## プロジェクトを作る

次にプロジェクトを作ります。

プロジェクト名は何でもかまわないのですが、今回は`simple`にしたとして話をすすめます。

コマンドラインから、

  > meteor create simple
  > cd simple

と入力してください。
これでプロジェクトフォルダができました。
さらに、プロジェクトフォルダを覗いてみます。

  > ls
  > simple.css simple.html  simple.js

上記のように、3つのファイルが出来ていれば成功です。

## jQueryを追加

今回のプロジェクトではjQueryを使います。
早速追加してみましょう。

コマンドラインから、

  > meteor add jquery

と入力してください。
これでjQueryが使えるようになりました。

それでは、最後にMeteorを起動します。

  > meteor

`http://localhost:3000/`にアクセスしてみてください。
下記のような画面が表示されていれば、準備完了です。

![最初はhello world](http://img.dfm.lrv.jp/meteor3/sc2.png)

# いよいよコードを書いてみる（HTML,JavaScript）

それでは、コードを書いていきましょう。
今回は、simple.htmlとsimple.jsを書きかえてみます。

書き換えるには、HTMLやJavaScriptの基本的な知識が必要です。
下記サイトを参考にしながら進めてください。

**HTMLやJavaScriptを優しく教えてくれる参考サイト**

- [0から始めるHTMLとCSSの基本・基礎-webデザイン入門](http://endoutakae.com/2012/02/08/webdesign/)
- [初心者のためのJavaScript入門](http://www.atmarkit.co.jp/fcoding/index/js.html)

  > しっかりマスターしてからでないと進められない、というものではないので、判らない部分が出て来たら調べる感じで進めてしまいましょう。

## CSSは?

simple.cssについての説明は今回サボりますw

下記をコピペしといてください。
もちろん、もっとカッコよい見た目を目指して好きなように書き換えて頂いてかまいません。

```simple.css
*{padding:0px;margin:0px;word-break:break-all!important;box-sizing:border-box!important;font-size:14px;}
body{background-color: #FFF;}
#head{padding:10px;background-color: #CFA!important;color:#000!important;}
#h_title{font-size:24px;}
#wrap{padding:5px;margin:0 auto;max-width:640px;color:#FFF;}
#postmes{width:320px;}
#postname{width:120px;}
#head{background-color: #000;color:#FFF;}
.rec_wrap{margin:5px;padding:5px 10px;color:#000;margin-bottom:10px;}
.rec_date{float:left;font-size:10px;width:100px;}
.rec_name{float:left;font-size:10px;width:120px;}
.rec_mes{clear:left;font-size: 20px;}
#control{clear:left;}
#colorbox{display:inline-block;vertical-align: middle;width:14px;height:14px;}
```

## HTMLを編集

それでは、`simple.html`から書いていきましょう。
何も編集しいない状態ですと、下記のようになっているはずです。

```simple.html
<head>
  <title>simple</title>
</head>

<body>
  {{> hello}}
</body>

<template name="hello">
  <h1>Hello World!</h1>
  {{greeting}}
  <input type="button" value="Click" />
</template>
```

### ちょっと待った。なんか変だぞ？このHTML

そうなんです！meteorで使うHTMLは少し変なんです。

1. `<html></html>`とか無いよ？
1. `{{> hello}}`？ `{{greeting}}`？ なんなのこれ
1. `<template></template>` ？

いろいろ変ですね？

実はMeteorで使うHTMLは、普通のHTMLファイルではありません。
Meteorがテンプレートという機能を使って書き換える元となるファイルになっています。

まず、`<html></html>`などは、Meteorが自動生成しますので気にしないでください。
次に、`{{> hello}}`の部分は後で出てくる`<template></template>`に記載されているコードに置き換えられます。
最後の`{{greeting}}`の部分はMeteorが採用するテンプレート記法での変数で、JavaScriptで内容を設定できます。

このあたりの説明は、[体感！JavaScriptで超速アプリケーション開発 －Meteor完全解説 第4回　Meteor開発のテンプレート](http://gihyo.jp/dev/serial/01/meteor/0004)あたりに詳しく書いてありますので、そちらを参照してみてください。

### 今回どのように書き換える？

さて、`simple.html`を、以下のように書き換えます。

1. テンプレート名が`hello`なのはアレなので`contents`に変更
2. 今のテンプレートの内容は使わないので削除

すると、こんな↓感じになったはずです。

```simple.html
<head>
  <title>simple</title>
</head>

<body>
  {{> contents}}
</body>

<template name="contents">

</template>
```

これをベースに、チャットで使うコードを追加していきましょう。
必要なテンプレートを含めるように書いていきます。

テンプレート|役割
-----------|------
{{maxrec}}|表示最大件数
{{color}}|背景色のスタイル
{{messages}}|メッセージのリスト
{{datetime}}|日付
{{name}}|名前
{{message}}|本文

最終的にコードは下記のようになりました。

```simple.html
<head>
  <title>simple</title>
</head>

<body>
  {{> contents}}
</body>

<template name="contents">
  <div id="head">
    <div id="h_title">Meteorを使ったシンプルなチャットのデモです。</div>
    <div id="m_title">{{maxrec}}件まで表示されます。背景色は
      <span><div id="colorbox" style="{{color}}"></div></span>です。
    </div>
    <div id="control">
      <input id="postname" type="text" placeholder="enter your name">
      <input id="postmes" type="text" placeholder="enter message">
    </div>
  </div>
  <div id="wrap">
    <div id="messages">
    {{#each messages}}
      <div class="rec_wrap" style="{{style}}">
        <div class="rec_date" id="date{{_id}}">{{datetime}}</div>
        <div class="rec_name" id="name{{_id}}">{{name}}</div>
        <div class="rec_mes" id="mes{{_id}}">{{message}}</div>
     </div>
   {{/each}}
   </div>
  </div>
</template>
```

入力Box2つと、リスト表示エリアがあるだけのシンプルなものができました。

JavaScriptの編集に入る前に、一旦`http://localhost:3000/`にアクセスしてみてください。

![HTMLの編集が終わった状態での画面](http://img.dfm.lrv.jp/meteor3/sc3.png)

こんな感じで表示されましたか？

## JavaScriptを編集

それでは次に`simple.js`を編集します。
こちらも、最初は`hello World`の内容になっています。
(コメントは消してあります)

```simple.js
if (Meteor.isClient) {
  Template.hello.greeting = function () {
    return "Welcome to simple.";
  };

  Template.hello.events({
    'click input': function () {
      if (typeof console !== 'undefined')
        console.log("You pressed the button");
    }
  });
}

if (Meteor.isServer) {
  Meteor.startup(function () {
  });
}
```

最初にhelloテンプレートに関連するコードは一旦消しておきましょう。

```simple.js
if (Meteor.isClient) {
}

if (Meteor.isServer) {
  Meteor.startup(function () {
  });
}
```

上記コードをベースに追加していきたいと思います。

### 色指定や、レコード数を書いてみる。

簡単なところから始めましょう。
最初は、html側に書かれているレコード最大件数の変数`{{maxrec}}`と、背景色の変数`{{color}}`に値を設定してみましょう。
この処理は、クライアントコード（`if (Meteor.isClient) { }` の内側）に書きます。

最大件数を追加するには、下記のように書きます。

```js
var maxrec = 10;
Template.contents.maxrec = maxrec;  // 最大件数表示
```

これでHTML側にも最大件数が表示されるようになります。

`Template.contents.maxrec = maxrec`は、「{{> contents}}の中の{{maxrec}}にmaxrecを設定する」という処理になります。
この部分だけで最大件数を使うのであれば、`10`をそのまま設定してもかまわないのですが、後で別の箇所でも最大件数を使うことになるので、`maxrec`に入れておくことにします。

続けて、背景色部分です。

```js
var colors = [
  'Cornsilk','Aquamarine','LightPink','PaleGreen','Coral',
  'SpringGreen','Plum','LightSkyBlue','MistyRose','Turquoise'];
var color = "background-color:"+colors[(+new Date()) % 10]+";";
Template.contents.color = color;    // 背景色表示
```

まず、10個の色テーブルから、ランダムに1個を選んで、`background-color:`と合成して変数`color`に一旦設定したうえで、`Template.contents.color`にも設定します。

ここまで出来たら、`http://localhost:3000/`を確認してみましょう。

![最大件数と背景色を追加](http://img.dfm.lrv.jp/meteor3/sc4.png)

ソースコードから最大件数を、他の数字に変えると、`http://localhost:3000/`の表示もすぐに変わるはずです。
また、背景色はリロードの都度変わると思います。いろいろ変えてみてください。

確認ができたら先に進みましょう。

### コレクションを使ってみる

チャットの情報を貯めておくには、データベースが使いたいですね。
Meteorでは、コレクションという機能を使うこと簡単にデータベースを使うことができます。

早速コレクションを使ってみましょう。

#### コレクションの生成

最初にコレクションを1つ生成します。
このコレクションは、メッセージを貯めるものですので、`Messages`という名前にしましょう。

コレクションの生成には、`Meteor.Collection()`を使います。

`simple.js`の冒頭（`if (Meteor.isClient) {` より上）に、下記コードを追加します。

```js
var Messages = new Meteor.Collection('messages');
```
#### コレクションからリストを読み込んでテンプレートに表示する

次に、`Messages`コレクションからメッセージのリストを読み込んで、
テンプレートに流し込む処理を書いてみましょう。
この処理は、クライアントコード（`if (Meteor.isClient) { }` の内側）に書きます。

```js
  Template.contents.messages = function () {
    return Messages.find({},{sort:{date:-1}});
  };
```

このようになります。

`Messages.find({},{sort:{date:-1}})`で、Messagesコレクションに登録された全てのレコードを`date`というフィールドの逆順にソートしてクエリしています。
クエリ結果は配列のようなオブジェクト`cursor`形式で返されます。

この結果は、直接`Template.contents.messages`に設定しています。
HTML側には、`{{#each messages}}{{/each}}`と書かれていますが、#eachは指定された配列(cursorでも良い)のレコードの数だけ内側に書かれたコードをコピーします。

これにより、`Messages.find()`で取り出したデータの数に対応したDOMを作ることができます。

#### コレクションにデータ登録する

最後に、少しコードが多くなりますが、textboxから文字を取り出してコレクションにデータ登録する処理を書いてみましょう。
コレクションは、SQLなどと違って、ドキュメントにデータ登録する時に、そのドキュメントが持つフィールドを自由に決めることができます。
今回、`Messages`には下記フィールドを持たせることにします。

フィールド名|テンプレート側の変数名|  
-----------|------|-----
datetime|{{datetime}}|日付(YYYY/MM/DD TT:MM形式の文字列)
date|-|ソート用。テンプレートには使わない。
name|{{name}}|名前
message|{{message}}|本文
style|{{style}}|background-colorを設定(colorをコピーしている)

`datetime`、`name`、`message`、`style`はそのままテンプレートの変数に設定されます。

コードは下記のようになります。
クライアントコード（`if (Meteor.isClient) { }` の内側）に書きます。

```js
 // イベント処理
  Template.contents.events({
    'keydown input#postmes':function(ev){
      if(ev.keyCode == 13){ // 'enter' keyで確定
        var message = $("#postmes").val();
        if(message != ""){
          $("#postmes").val("");   // 入力Boxの文字消す。
          var setdata = createProperties(message); // データをつくる
          // コレクションへ新レコードを登録
          Messages.insert(setdata,function(err,_id){
            // 最大件数以上なら古いのを消す
            var len = Messages.find({}).fetch().length;
            if(len > maxrec){
              var doc = Messages.findOne({}); // 先頭レコード(つまり一番古いレコード)を取り出す
              Messages.remove({_id:doc._id}); // そして消す
            }
          });
        }
      } 
    }
  });

  // messageレコードのプロパティ生成
  function createProperties(message){
    var date = Date.parse(new Date());
    var datetime = toDateStr(date);
    var name = $("#postname").val();
    var style = color;
    if(name == ""){
      name = "guest";
    }
    return {date:date,datetime:datetime,message:message,name:name,style:style};
  }

  // 日付を文字列に変換
  function toDateStr(parseDate){
    var date = new Date(parseDate);
    var y = date.getFullYear();
    var m = date.getMonth()+1;
    var d = date.getDate();
    var h = date.getHours();
    var min = date.getMinutes();
    return y+"/"+m+"/"+d+" "+h+":"+min;
  }
```

ここだけちょっと長かったですね。申し訳ありません。
少し解説します。

##### Template.contents.events()

これはイベントハンドラです。
今回は、ID `#postmes` のテキストボックスで改行キー（enterキー）を押したらイベント処理を行うように設定しています。
jQueryを使ってテキストボックスに入力されたテキストを取得し、何も入力されてなかったら、登録しないよう条件を入れています。
これは、連続改行連打とかで酷いことになるのを防止するためです。
テキストボックスに何か、文字が入っていたら、`createProperties()`を使って登録データを生成後、`Messages.insert()`を使ってコレクションにデータを登録しています。

##### createProperties()

Messagesへ登録するドキュメント(1レコード)のデータを生成しています。

##### Messages.insert()

Messagesへデータ登録を行っています。
非同期で呼び出されるコールバックの中では、Messagesに登録されたドキュメントの件数を求めて、`maxrec`を超えてないかチェックしています。
超えてたら、`Messages.remove()`を使って1件削除しています。
なので、厳密に言うと、`maxrec`は「表示件数の上限」ではなくて、「データ登録件数の上限」なんですねw

#### コレクションの初期化

なぜか、一番最後になってしまいましたが、コレクションの初期化処理について書きます。
コレクションの初期化処理は、サーバ側コード（`if (Meteor.isServer) { }` の内側）に書きます。

これまで、`Meteor.startup()`（アプリを立ち上げると動作する処理）には何も書かれていませんでしたが、下記コードを追加しておきます。

```js
  Meteor.startup(function () {
    Messages.remove({});  // 全クリア
  });
```

`Messages.remove({})` で全ドキュメント（レコード）がクリアされます。

もし、開発が終わったら、この部分は他の方法で実装した方が良いと思いますw

## 一応完成のはず。

完成しましたか？
完成しねーぞごら！という方は、申し訳ありませんが[このようなコードですが、githubにも上げておきました](https://github.com/tadfmac/meteor-simple-board)から引っ張ってやってみてくださいw

# まとめ。

今回は、簡単に作ることを目指したので、コレクションの使い方もかなりいい加減なものになっています。
しかし、引き換えに本当に簡単にチャットが作れました。

いろいろと説明がヘタ、不足などあると思いますので、ご指摘、質問よろしくお願いします！

たぶん、(4)も書くと思います。
どっかでPixi.jsとの連携もやりたいなーw

## バックナンバーと続き

下記もよろしくお願いします！

[JavaScript超初心者向け Meteor メモ (1)](http://qiita.com/tadfmac/items/a63bb85e5cfb12bbbfc8)
[JavaScript超初心者向け Meteor メモ (2) v0.8.0でのテンプレートエンジンの変更について](http://qiita.com/tadfmac/items/823fd909bf3af2f6c7b7)
[JavaScript超初心者向け Meteor メモ (4) ログイン画面を作る （基本編）](http://qiita.com/tadfmac/items/714654958c127c053d51)
[JavaScript超初心者向け Meteor メモ (5) ログイン画面を作る （Google/Twitterアカウント編）](http://qiita.com/tadfmac/items/5bfe73f181f9b45abe71)
[JavaScript超初心者向け Meteor メモ (6) 外部パッケージを使ってみる](http://qiita.com/tadfmac/items/48d160ecba779237c771)
[JavaScript超初心者向け Meteor メモ (7) テンプレートを使ってみる](http://qiita.com/tadfmac/items/2b5e111e8986fc98f6f8)