チュートリアルからMeteorを学習したメモ

# 概要

[Meteor Tutorial | Creating an app] (https://www.meteor.com/tutorials/blaze/creating-an-app)を参考に、雛形のアプリケーションにちょっとずつ修正を入れていきながらMeteorの使い方を学習したメモです。

**環境**

* Windows7 (64bit)
* Meteor 1.2.0.2

**参考**

* [Meteor] (https://www.meteor.com/)
* [Documentation - Meteor] (http://docs.meteor.com/#/full/)
* [Discover Meteor] (https://www.discovermeteor.com/)
* [Discover Meteor (日本語版)] (http://ja.discovermeteor.com/)

**Meteor 1.2**

* [ECMAScript2015] (http://www.ecma-international.org/ecma-262/6.0/index.html) (ES6)
* Official support for Angular and React.
* Cordova has been updated to 5.2.0.


## 1. プロジェクトの雛形を作成する

チュートリアル: [Creating your first app] (https://www.meteor.com/tutorials/blaze/creating-an-app)

meteor createコマンドでプロジェクトの雛形を作成します。

```bat:create
> meteor create mt-example
Created a new Meteor app in 'mt-example'.

To run your new app:
  cd mt-example
  meteor

If you are new to Meteor, try some of the learning resources here:
  https://www.meteor.com/learn
```

### 実行

プロジェクトディレクトリへ移動しmeteorコマンドを実行するとアプリケーションが起動します。

```bat:run
> cd mt-example
> meteor
[[[[[ ~\D\dev\mt-example ]]]]]

=> Started proxy.
=> Started MongoDB.
=> Started your app.

=> App running at: http://localhost:3000/
   Type Control-C twice to stop.
```

### ここまでの成果

アプリケーションが起動したら下記のURLにアクセスします。

http://localhost:3000/

下図のページが表示されれば成功です。

![m04.png](https://qiita-image-store.s3.amazonaws.com/0/22772/68c7b7c6-2fcc-8977-6d30-d46f72f621ce.png)


### ソースコード

meteor createコマンドで生成されたソースコードは下記の通りです。

**mt-example.html**

```html
<head>
  <title>mt-example</title>
</head>

<body>
  <h1>Welcome to Meteor!</h1>

  {{> hello}}
</body>

<template name="hello">
  <button>Click Me</button>
  <p>You've pressed the button {{counter}} times.</p>
</template>
```

**mt-example.js**

```js
if (Meteor.isClient) {
  // counter starts at 0
  Session.setDefault('counter', 0);

  Template.hello.helpers({
    counter: function () {
      return Session.get('counter');
    }
  });

  Template.hello.events({
    'click button': function () {
      // increment the counter when button is clicked
      Session.set('counter', Session.get('counter') + 1);
    }
  });
}

if (Meteor.isServer) {
  Meteor.startup(function () {
    // code to run on server at startup
  });
}
```

**mt-example.css**

cssはチュートリアルの[Defining views with templates] (https://www.meteor.com/tutorials/blaze/templates)に記載されているcssの内容で書き換えます。

```css
/* CSS declarations go here */
```


## 2. タスクを表示する

チュートリアル: [Defining views with templates] (https://www.meteor.com/tutorials/blaze/templates)

**テンプレート**

```html:mt-example.html
<body>
  <!--追加-->
  <div class="container">
  <!--追加-->

...省略...

  <!--追加-->
  <div>
    <ul>
    {{#each tasks}}
      {{> task}}
    {{/each}}
    </ul>
  </div>
  <!--追加-->

...省略...

  <!--追加-->
  </div>
  <!--追加-->
</body>
```

`{{> task}}`はtaskという名前のテンプレートが差し込まれる場所を示すプレースホルダの役割を果たします。

***テンプレートの定義***

この`{{> task}}`に差し込まれるテンプレートをtemplateタグで定義します。
name属性にはテンプレートの名前を記述します。
`{{no}}`と`{{text}}`は下記のhelpersで定義するtasksオブジェクトのフィールドの値を出力します。

```html:mt-example.html
<!--追加-->
<template name="task">
  <li>No.{{no}} {{text}}</li>
</template>
<!--追加-->
```

***body***

bodyタグも一種のテンプレートとして扱われます。
下記はbodyタグ(テンプレート)内から参照できるtasks変数を定義しています。ほかのテンプレートからは参照できません。

```js:mt-example.js
if (Meteor.isClient) {
...省略...

  //追加
  Template.body.helpers({
    tasks: [
      { text: "This is task.", no:1 },
      { text: "This is task.", no:2 },
      { text: "This is task.", no:3 },
      { text: "This is task.", no:4 }
    ]
  });
  //追加

...省略...
}
```

### Template.templateName.helpers

helpersはテンプレートヘルパーを定義します。
ヘルパーにはテンプレート内で使用できるデータや関数を登録することができます。

`Template.templateName.helpers(helpers)`

引数

* helpers : Object

### ここまでの成果

コードを修正するとブラウザのリロードをすることなく下図のページが表示されていると思います。

![m05.png](https://qiita-image-store.s3.amazonaws.com/0/22772/e1ce7ddf-430f-6b9f-0c33-9337e48d13dc.png)



## 3. MongoDBからタスクデータを取得する

チュートリアル: [Storing tasks in a collection] (https://www.meteor.com/tutorials/blaze/collections)

### mongo shell

meteor mongoコマンドでmongo shellを起動することができます。
データファイルはmt-example/.meteor/local/dbディレクトリに作成されます。

```bat:mongo
> meteor mongo
MongoDB shell version: 2.6.7
connecting to: 127.0.0.1:3001/meteor
Server has startup warnings:
2015-10-11T01:20:12.244+0900 [initandlisten]
2015-10-11T01:20:12.244+0900 [initandlisten] ** NOTE: This is a 32 bit MongoDB binary.
2015-10-11T01:20:12.244+0900 [initandlisten] **       32 bit builds are limited to less than 2GB of data (or less with --journal).
2015-10-11T01:20:12.244+0900 [initandlisten] **       Note that journaling defaults to off for 32 bit and is currently off.
2015-10-11T01:20:12.244+0900 [initandlisten] **       See http://dochub.mongodb.org/core/32bit
2015-10-11T01:20:12.244+0900 [initandlisten]
meteor:PRIMARY>
```

**タスクデータの追加**

タスクの初期データを追加します。

```bat:insert
meteor:PRIMARY> db.tasks.insert({ text: "掃除", no: 1, createdAt: new Date() });
WriteResult({ "nInserted" : 1 })
meteor:PRIMARY> db.tasks.insert({ text: "洗濯", no: 2, createdAt: new Date() });
WriteResult({ "nInserted" : 1 })
meteor:PRIMARY> db.tasks.insert({ text: "ゴミだし", no: 3, createdAt: new Date() });
WriteResult({ "nInserted" : 1 })
meteor:PRIMARY> db.tasks.insert({ text: "買い物", no: 4, createdAt: new Date() });
WriteResult({ "nInserted" : 1 })
```

登録したデータを確認します。

```bat:find
meteor:PRIMARY> db.tasks.find({},{_id:0,text:1,no:1});
{ "text" : "掃除", "no" : 1 }
{ "text" : "洗濯", "no" : 2 }
{ "text" : "ゴミだし", "no" : 3 }
{ "text" : "買い物", "no" : 4 }
```

**js**

jsからはMongo.Collection APIを使用してMongoDBのデータにアクセスすることができます。

```js:mt-example.js
//追加
Tasks = new Mongo.Collection("tasks");
```

tasksをMongoDBからの検索結果に変更します。

```js:mt-example.js
if (Meteor.isClient) {
...省略...

  Template.body.helpers({

    /* コメントアウト
    tasks: [
      { text: "This is task.", no:1 },
      { text: "This is task.", no:2 },
      { text: "This is task.", no:3 },
      { text: "This is task.", no:4 }
    ]
    */

    //追加
    tasks: function() {
      return Tasks.find({});
    }
    //追加

  });

...省略...
}
```

### Mongo.collection.find

Mongo.collection APIのfindの構文はmongo shellのfindとは違いますので、mongo shellでそのまま実行するとエラーになります。

***Mongo.collection API***

```Usage
collection.find([selector], [options])
```

***mongo shell***

```Usage
db.collection.find(<query>, <projection>)
```

引数

* selector : Mongo Selector, Object ID, or String
* options
 * sort : Mongo Sort Specifier
 * skip : number
 * limit : number
 * fields : Mongo Field Specifier
 * reactive : boolean
 * transform : function

***例***

```js:例
Tasks.find({}, {sort:{createdAt: -1}, skip:0, limit:10, fields:{_id:1, text:1, no:1} });
```

### ここまでの成果

自動的にブラウザがリロードされ、MongoDBに登録したデータが表示されていると思います。

![m06.png](https://qiita-image-store.s3.amazonaws.com/0/22772/03637b5e-149e-8afa-b226-a8e1dd88dabf.png)


### mongoコマンド

基本的なMongoDBのコマンドが使用できます。

***例***

```bat:dbs
meteor:PRIMARY> show dbs;
admin   (empty)
local   0.063GB
meteor  0.031GB
```

```bat:collections
meteor:PRIMARY> show collections;
system.indexes
tasks
```

```bat:stats
meteor:PRIMARY> db.stats();
```

```bat:find
meteor:PRIMARY> db.tasks.find().limit(1).pretty();
```

```bat:count
meteor:PRIMARY> db.tasks.find().count();
```

```bat:gte
meteor:PRIMARY> db.tasks.find({no: {$gte: 3}});
```

```bat:sort
meteor:PRIMARY> db.tasks.find().sort({no:-1});
```


### resetコマンド

meteor resetコマンドを実行するとMongoDBのデータをリセットします。

```bat:reset
> meteor reset
Project reset.
```

アプリケーションの実行中はresetできません。

```bat:reset
> meteor reset
reset: Meteor is running.

This command does not work while Meteor is running your application. Exit the running Meteor development server.
```


## 4. フォームからタスクを登録する

チュートリアル: [Adding tasks with a form] (https://www.meteor.com/tutorials/blaze/forms-and-events)

**テンプレート**

タスクを登録するフォームを加えます。

```html:mt-example.html
<body>
...省略...

  <!--追加-->
  <div>
    <form>
      <input type="text" name="text" placeholder="Type to new task name" />
      <input type="text" name="no" placeholder="Type to new task no" />
      <input type="submit" value="create" />
    </form>
  </div>
  <!--追加-->

  <div>
    <ul>
    {{#each tasks}}
      {{> task}}
    {{/each}}
    </ul>
  </div>

...省略...
</body>
```

**イベントの定義**

submitボタンが押されたときの処理のイベントを定義します。
`Tasks.insert({...})`でタスクを追加すると自動的にブラウザの方に追加したタスク反映されます。

```js:mt-example.js
if (Meteor.isClient) {
...省略...

  //追加
  Template.body.events({
    "submit form": function (event, template) {
      // Prevent default browser form submit
      event.preventDefault();
      // Get value from form element
      var text = event.target.text.value;
      var no = event.target.no.value;
      // Insert a task into the collection
      Tasks.insert({
        _id: new Meteor.Collection.ObjectID(),
        text: text,
        no: no,
        createdAt: new Date() // current time
      });
      // Clear form
      event.target.text.value = "";
      event.target.no.value= "";
    }
  });
  //追加

}
```

### Template.templateName.events

eventsでテンプレートにイベントハンドラーを定義します。

`Template.templateName.events(eventMap)`

引数

* eventMap : Event Map

#### Event Map

* keyには"イベント名 CSSセレクター"または"イベント名"を指定します。カンマ区切りで複数のイベントを指定することができます。
* valueにはイベントハンドラーを定義します。

***例***

formのsubmitボタンが押されたときに実行されるイベントです。

```js:例
{
  "submit form": function (event, template) {
    ...なにかの処理...
  }
}
```

***イベント名***

> The first part of the key (before the first space) is the name of the event being captured.
>
> Some common ones
>
> * click
> * mousedown
> * mouseup
> * mouseenter
> * mouseleave
> * keydown
> * keyup
> * keypress
> * focus
> * blur
> * change

***CSSセレクター***

> The second part of the key (after the first space) is a CSS selector that indicates which elements to listen to.


### ここまでの成果

タスク名とNoを入力してcreateボタンをクリックするとタスク一覧に反映されます。

![m08.png](https://qiita-image-store.s3.amazonaws.com/0/22772/7f3a4ef7-1218-f835-7c1c-15d5d58fc4cc.png)



## 5. タスクの更新と削除

チュートリアル: [Checking off and deleting tasks] (https://www.meteor.com/tutorials/blaze/update-and-remove)

**テンプレート**

タスクの一覧に実行済みチェックボックスと削除用のボタンを追加します。

```html:mt-example.html
<template name="task">
  <!--追加-->
  <li class="{{#if checked}}checked{{/if}}">
    <button class="delete">&times;</button>
    <input type="checkbox" checked="{{checked}}" class="toggle-checked" />
    <span class="text">No.{{no}} {{text}}</span>
  </li>
  <!--追加-->
  <!--コメントアウト
  <li>No.{{no}} {{text}}</li>
  -->
</template>
```

**イベントの定義**

実行済みチェックボックスにチェックを入れるとTasksコレクションのcheckedフィールドが"true" or "false"で更新されます。

```js:mt-example.js
if (Meteor.isClient) {
...省略...

  //追加
  Template.task.events({
    "click .toggle-checked": function (event, template) {
      // Set the checked property to the opposite of its current value
      Tasks.update(this._id, {
        $set: {checked: ! this.checked, updatedAt: new Date()}
      });
    },
    "click .delete": function () {
      Tasks.remove(this._id);
    }
  });
  //追加

...省略...
}
```

### thisが指すもの

Template.task.eventsの中で`this`が指すものは下記のhelpersで取得したコレクション(の1行)です。

> Inside the event handlers, this refers to an individual task object.
> In a collection, every inserted document has a unique \_id field that can be used to refer to that specific document.

```js:mt-example.js
Template.body.helpers({
  tasks: function() {
    return Tasks.find({});
  }
});
```

findを下記のように書き換えるとcheckedフィールドが参照できなくなるため、チェックボックスのcheckedの設定が出来なくなります。

```js:mt-example.js
Template.body.helpers({
  tasks: function() {
    return Tasks.find({}, {fields:{_id:1, text:1, no:1, checked:0} });
  }
});
```

### ここまでの成果

タスクの左側のチェックボックスにチェックを入れると実行済みとして表示します。
タスクの右側のxをクリックするとタスクを削除します。

![m09.png](https://qiita-image-store.s3.amazonaws.com/0/22772/aeaa7e8f-e454-f515-1df1-7ed294990fdb.png)



## 6. UIの状態をセッションで管理する

チュートリアル: [Storing temporary UI state in Session] (https://www.meteor.com/tutorials/blaze/temporary-ui-state)

Session APIを使用するとセッションにUIの状態を保存することができます。
ブラウザを手動でリロードするとセッションの状態がリセットされます。

**テンプレート**

```html:mt-example.html
<body>
...省略...

  <!--追加-->
  <div>
    <h2>Todo List ({{incompleteCount}})</h2>
    <label class="hide-completed">
      <input type="checkbox" checked="{{hideCompleted}}" />
      Hide Completed Tasks
    </label>
  </div>
  <!--追加-->

...省略...
</body>
```

**イベントの定義**

チェックボックスの状態を"hideCompleted"という名前のセッションで管理します。

```js:mt-example.js
//追加
Session.setDefault("hideCompleted", false);
```

チェックボックスのchangeイベントにセッションの更新処理を設定します。

```js:mt-example.js
if (Meteor.isClient) {
...省略...

  Template.body.events({
    ...省略...

    //追加
    "change .hide-completed input": function (event) {
      Session.set("hideCompleted", event.target.checked);
    }
    //追加
  });

...省略...
}
```

Session.getで"hideCompleted"セッションの値を取得します。

```js:mt-example.js
if (Meteor.isClient) {
...省略...

  Template.body.helpers({
    ...省略...

    //追加
    hideCompleted: function () {
      return Session.get("hideCompleted");
    },
    incompleteCount: function () {
      return Tasks.find({checked: {$ne: true}}).count();
    }
    //追加
  });

...省略...
}
```


### ここまでの成果

![m10.png](https://qiita-image-store.s3.amazonaws.com/0/22772/90184e1d-fb9b-ed09-7398-910d5221651c.png)

Hide Completed Tasksにチェックを入れるとタスクのフィルタリングを行います。

![m11.png](https://qiita-image-store.s3.amazonaws.com/0/22772/447a1163-ba14-9392-90d9-23fd391725f3.png)



## 7. ユーザーアカウント

チュートリアル: [Adding user accounts] (https://www.meteor.com/tutorials/blaze/adding-user-accounts)

### パッケージの追加

accounts-ui、accounts-passwordパッケージを追加します。

```bat:add
> meteor add accounts-ui accounts-password

Changes to your project's package version selections:

accounts-base          added, version 1.2.1
accounts-password      added, version 1.1.3
accounts-ui            added, version 1.1.6
accounts-ui-unstyled   added, version 1.1.8
ddp-rate-limiter       added, version 1.0.0
email                  added, version 1.0.7
less                   added, version 2.5.0_3
localstorage           added, version 1.0.5
npm-bcrypt             added, version 0.7.8_2
rate-limit             added, version 1.0.0
service-configuration  added, version 1.0.5
sha                    added, version 1.0.4
srp                    added, version 1.0.4


accounts-ui: Simple templates to add login widgets to an app
accounts-password: Password support for accounts
```


**テンプレート**

`{{> loginButtons}}`はaccounts-uiパッケージで提供されているテンプレートです。

```html:mt-example.html
<body>
...省略...

  <div>
    <!--追加-->
    {{> loginButtons}}
    <!--追加-->

    <!--追加-->
    {{#if currentUser}}
    <!--追加-->
    <form>
      <input type="text" name="text" placeholder="Type to new task name" />
      <input type="text" name="no" placeholder="Type to new task no" />
      <input type="submit" value="create" />
    </form>
    <!--追加-->
    {{/if}}
    <!--追加-->
  </div>

...省略...
</body>
```

タスク名の前にユーザー名を表示するように修正します。

```html:mt-example.html
<template name="task">

  <li class="{{#if checked}}checked{{/if}}">
    <button class="delete">&times;</button>
    <input type="checkbox" checked="{{checked}}" class="toggle-checked" />
    <!--コメントアウト
    <span class="text">No.{{no}} {{text}}</span>
    -->
    <!--追加-->
    <span class="text"><strong>{{username}}</strong> - No.{{no}} {{text}}</span>
    <!--追加-->
  </li>
</template>
```

**Accounts.uiの設定**

```js:mt-example.js
if (Meteor.isClient) {
...省略...

  //追加
  Accounts.ui.config({
    passwordSignupFields: "USERNAME_ONLY"
  });
  //追加

...省略...
}
```

`Accounts.ui.config(options)`

引数

* options
 * requestPermissions : Object
 * requestOfflineToken : Object
 * forceApprovalPrompt : Object
 * passwordSignupFields : String


***passwordSignupFields***

|field                       |description                        |
|:---------------------------|:-----------------------------------|
|USERNAME_AND_EMAIL          |ユーザー名とメールアドレス            |
|USERNAME_AND_OPTIONAL_EMAIL |ユーザー名、メールアドレス(オプション) |
|USERNAME_ONLY               |ユーザー名                           |
|EMAIL_ONLY                  |default. メールアドレス              |


***例***

```js:例
Accounts.ui.config({
  requestPermissions: {
    facebook: ['user_likes'],
    github: ['user', 'repo']
  },
  requestOfflineToken: {
    google: true
  },
  passwordSignupFields: 'USERNAME_AND_OPTIONAL_EMAIL'
});
```


**イベントの定義**

タスク登録時にTasksコレクションのフィールドにownerとusernameを追加します。

```js:mt-example.js
if (Meteor.isClient) {
...省略...

  Template.body.events({

    ...省略...

    // Insert a task into the collection
    Tasks.insert({
      _id: new Meteor.Collection.ObjectID(),
      text: text,
      no: no,
      createdAt: new Date(), // current time
      owner: Meteor.userId(),           // _id of logged in user
      username: Meteor.user().username  // username of logged in user
    });

    ...省略...

  });

...省略...
}
```

***Meteor.userId()***

現在のユーザーのユーザーIDを取得します。ログインしていなければnullを返します。

***Meteor.user()***

Meteor.usersコレクションから現在のユーザーのユーザーレコードを取得します。




### ここまでの成果

"Sign in"というリンクテキストが表示されます。
また、未ログイン状態なのでタスクの登録フォームは表示されません。

![m12.png](https://qiita-image-store.s3.amazonaws.com/0/22772/d59f33ea-6e12-5eb7-f54c-5db6b6841200.png)

"Sign in"というリンクテキストをクリックするとログインフォームが表示されます。
まだアカウントが無いので下の"Create account"をクリックします。

![m13.png](https://qiita-image-store.s3.amazonaws.com/0/22772/7bb1695b-0dd4-d970-5063-6f04c8f260f2.png)

ユーザー情報を入力してCreate accountボタンをクリックします。

![m14.png](https://qiita-image-store.s3.amazonaws.com/0/22772/8abd8e2e-96c2-acce-9cee-dde716331fad.png)

アカウントを登録するとカレントユーザー名が表示されます。
この状態でタスクを登録するとタスク名の前にユーザー名が表示されます。

![m15.png](https://qiita-image-store.s3.amazonaws.com/0/22772/96b5f84d-c794-c908-70b6-2f8b809d6edf.png)


### usersコレクション

アカウントはMongoDBにusersという名前のコレクションに格納されます。

```bat:collections
meteor:PRIMARY> show collections;
meteor_accounts_loginServiceConfiguration
system.indexes
tasks
users
```

```bat:users
meteor:PRIMARY> db.users.find().pretty();
{
        "_id" : "fstArzrP8wf5iP3pA",
        "createdAt" : ISODate("2015-10-14T10:21:49.138Z"),
        "services" : {
                "password" : {
                        "bcrypt" : "$2a$10$DmNDKCT5j7eRIkesXAsMl.r5lMRyEV2y7CTccT4q/IUZGLrNFvB6."
                },
                "resume" : {
                        "loginTokens" : [
                                {
                                        "when" : ISODate("2015-10-14T10:21:49.143Z"),
                                        "hashedToken" : "FVQPWioxV92XvJQtD/9rrcNybtUUh6QZY7ALjTwTMwQ="
                                }
                        ]
                }
        },
        "username" : "rubytomato"
}
```


## 8. セキュリティ

チュートリアル: [Security with methods] (https://www.meteor.com/tutorials/blaze/security-with-methods)

### パッケージの削除

insecureパッケージを削除します。

```bat:remove
> meteor remove insecure

Changes to your project's package version selections:

insecure  removed from your project

insecure: removed dependency
```

insecureパッケージがあるとchromeのコンソールなどからCollection APIを直接呼び出すことが可能です。

![m16.png](https://qiita-image-store.s3.amazonaws.com/0/22772/784d16e7-264b-2341-c2d5-2545f18f2704.png)

登録したデータはそのままブラウザに反映されます。

![m17.png](https://qiita-image-store.s3.amazonaws.com/0/22772/0fc89251-dcff-84fb-8808-cfc5a72529cf.png)

insecureパッケージを削除するとAPIを呼び出せないようになります。

![m18.png](https://qiita-image-store.s3.amazonaws.com/0/22772/234ea75c-3173-1fac-171d-9c8be4ccb8a2.png)


**メソッド**

Meteor.methodsで定義する関数はサーバーとクライアントの両方から呼び出すことができます。

```js:mt-example.js
//追加
Meteor.methods({
  addTask: function (text, no) {
    // Make sure the user is logged in before inserting a task
    if (! Meteor.userId()) {
      throw new Meteor.Error("not-authorized");
    }
    Tasks.insert({
      _id: new Meteor.Collection.ObjectID(),
      text: text,
      no: parseInt(no,10),
      createdAt: new Date(),
      owner: Meteor.userId(),
      username: Meteor.user().username
    });
  },
  deleteTask: function (taskId) {
    Tasks.remove(taskId);
  },
  setChecked: function (taskId, setChecked) {
    Tasks.update(taskId, { $set: { checked: setChecked} });
  }
});
//追加
```

**イベントの定義**

メソッドを呼び出すように修正します。

```js:mt-example.js
if (Meteor.isClient) {
...省略...

  Template.body.events({
    ...省略...

    //追加
    // Insert a task into the collection
    Meteor.call("addTask", text, no);
    //追加

    /*
    // Insert a task into the collection
    Tasks.insert({
      _id: new Meteor.Collection.ObjectID(),
      text: text,
      no: no,
      createdAt: new Date(), // current time
      owner: Meteor.userId(),           // _id of logged in user
      username: Meteor.user().username  // username of logged in user
    });
    */


    ...省略...
  });

  Template.task.events({
    "click .toggle-checked": function (event, template) {
      //追加
      // Set the checked property to the opposite of its current value
      Meteor.call("setChecked", this._id, ! this.checked);
      //追加
      /*
      // Set the checked property to the opposite of its current value
      Tasks.update(this._id, {
        $set: {checked: ! this.checked}
      });
      */
    },
    "click .delete": function () {
      //追加
      Meteor.call("deleteTask", this._id);
      //追加
      /*
      Tasks.remove(this._id);
      */
    }
  });

...省略...
}
```

### ここまでの成果

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


**mt-example.html**

```html
<head>
  <title>mt-example</title>
</head>

<body>
  <div class="container">
  <h1>Welcome to Meteor!</h1>

  {{> hello}}

  <div>
    <h2>Todo List ({{incompleteCount}})</h2>
    <label class="hide-completed">
      <input type="checkbox" checked="{{hideCompleted}}" />
      Hide Completed Tasks
    </label>
  </div>

  <div>
    <div>
      {{> loginButtons}}
    </div>

    {{#if currentUser}}
    <form>
      <input type="text" name="text" placeholder="Type to new task name" />
      <input type="text" name="no" placeholder="Type to new task no" />
      <input type="submit" value="create" />
    </form>
    {{/if}}
  </div>

  <div>
    <ul>
    {{#each tasks}}
      {{> task}}
    {{/each}}
    </ul>
  </div>

  </div>
</body>

<template name="hello">
  <button>Click Me</button>
  <p>You've pressed the button {{counter}} times.</p>
</template>

<template name="task">
  <li class="{{#if checked}}checked{{/if}}">
    <button class="delete">&times;</button>
    <input type="checkbox" checked="{{checked}}" class="toggle-checked" />
    <span class="text"><strong>{{username}}</strong> - No.{{no}} {{text}}</span>
  </li>
</template>
```

**mt-example.js**

```js
Tasks = new Mongo.Collection("tasks");

if (Meteor.isClient) {
  // counter starts at 0
  Session.setDefault('counter', 0);
  Session.setDefault('hideCompleted', false);

  Template.hello.helpers({
    counter: function () {
      return Session.get('counter');
    }
  });

  Template.hello.events({
    'click button': function () {
      // increment the counter when button is clicked
      Session.set('counter', Session.get('counter') + 1);
    }
  });

  Template.body.helpers({
    tasks: function() {
      if (Session.get("hideCompleted")) {
        // If hide completed is checked, filter tasks
        return Tasks.find({checked: {$ne: true}}, {sort: {createdAt: -1}});
      } else {
        // Otherwise, return all of the tasks
        return Tasks.find({}, {sort: {createdAt: -1}});
      }
    },
    hideCompleted: function () {
      return Session.get("hideCompleted");
    },
    incompleteCount: function () {
      return Tasks.find({checked: {$ne: true}}).count();
    }
  });

  Template.body.events({
    "submit form": function (event, template) {
      // Prevent default browser form submit
      event.preventDefault();
      // Get value from form element
      var text = event.target.text.value;
      var no = event.target.no.value;
      // Insert a task into the collection
      Meteor.call("addTask", text, no);
      // Clear form
      event.target.text.value = "";
      event.target.no.value= "";
    },
    "change .hide-completed input": function (event) {
      Session.set("hideCompleted", event.target.checked);
    }
  });

  Template.task.events({
    "click .toggle-checked": function (event, template) {
      // Set the checked property to the opposite of its current value
      Meteor.call("setChecked", this._id, ! this.checked);
    },
    "click .delete": function () {
      //Tasks.remove(this._id);
      Meteor.call("deleteTask", this._id);
    }
  });

  Accounts.ui.config({
    passwordSignupFields: "USERNAME_ONLY"
  });
}

if (Meteor.isServer) {
  Meteor.startup(function () {
    // code to run on server at startup
  });
}

Meteor.methods({
  addTask: function (text, no) {
    // Make sure the user is logged in before inserting a task
    if (! Meteor.userId()) {
      throw new Meteor.Error("not-authorized");
    }
    Tasks.insert({
      _id: new Meteor.Collection.ObjectID(),
      text: text,
      no: parseInt(no,10),
      createdAt: new Date(),
      owner: Meteor.userId(),
      username: Meteor.user().username
    });
  },
  deleteTask: function (taskId) {
    Tasks.remove(taskId);
  },
  setChecked: function (taskId, setChecked) {
    Tasks.update(taskId, { $set: { checked: setChecked, updatedAt: new Date()} });
  }
});
```

**使用パッケージ**

```bat:packages
> meteor list
accounts-password     1.1.3  Password support for accounts
accounts-ui           1.1.6  Simple templates to add login widgets to an app
autopublish           1.0.4  (For prototyping only) Publish the entire database to all clients
blaze-html-templates  1.0.1  Compile HTML templates into reactive UI with Meteor Blaze
ecmascript            0.1.5  Compiler plugin that supports ES2015+ in all .js files
es5-shim              4.1.13  Shims and polyfills to improve ECMAScript 5 support
jquery                1.11.4  Manipulate the DOM using CSS selectors
meteor-base           1.0.1  Packages that every Meteor app needs
mobile-experience     1.0.1  Packages for a great mobile user experience
mongo                 1.1.2  Adaptor for using MongoDB and Minimongo over DDP
session               1.1.1  Session variable
standard-minifiers    1.0.1  Standard minifiers used with Meteor apps by default.
tracker               1.0.9  Dependency tracker to allow reactive callbacks
```



## メモ

### インストール

[Installing Meteor on OS X, Linux and Windows] (https://www.meteor.com/install)よりWindows版のインストーラーをダウンロードして実行します。

ダウンロードファイル: InstallMeteor.exe

![m01.png](https://qiita-image-store.s3.amazonaws.com/0/22772/4fe30fd2-e522-619f-7e15-66fc8c67a737.png)

アカウントの登録が必要なければ、"Skip this step"でスキップすることができます。
今回はスキップしました。

![m02.png](https://qiita-image-store.s3.amazonaws.com/0/22772/051e5c8d-5c1a-4628-a4ee-e65413e63616.png)

インストール終了です。

![m03.png](https://qiita-image-store.s3.amazonaws.com/0/22772/41c7c5aa-64ef-17dd-9c6a-0bbdcaa6c50f.png)


### 初期状態

アプリケーションを作成した直後のディレクトリ／ファイルの状態

```text:tree
mt-example
├─mt-example.css
├─mt-example.html
├─mt-example.js
└─.meteor
    ├─packages
    ├─platforms
    ├─release
    ├─versions
    └─local
        ├─isopacks
        └─plugin-cache
            ├─autopublish
            │  └─1.0.4
            ├─autoupdate
            │  └─1.2.3
            ├─babel-compiler
            │  └─5.8.24_1
            ├─babel-runtime
            │  └─0.1.4
            ├─base64
            │  └─1.0.4
            ├─binary-heap
            │  └─1.0.4
            ├─blaze
            │  └─2.1.3
            ├─blaze-html-templates
            │  └─1.0.1
            ├─blaze-tools
            │  └─1.0.4
            ├─boilerplate-generator
            │  └─1.0.4
            ├─caching-compiler
            │  └─1.0.0
            ├─caching-html-compiler
            │  └─1.0.2
            ├─callback-hook
            │  └─1.0.4
            ├─check
            │  └─1.0.6
            ├─ddp
            │  └─1.2.2
            ├─ddp-client
            │  └─1.2.1
            ├─ddp-common
            │  └─1.2.1
            ├─ddp-server
            │  └─1.2.1
            ├─deps
            │  └─1.0.9
            ├─diff-sequence
            │  └─1.0.1
            ├─ecmascript
            │  └─0.1.5
            ├─ecmascript-collections
            │  └─0.1.6
            ├─ejson
            │  └─1.0.7
            ├─es5-shim
            │  └─4.1.13
            ├─fastclick
            │  └─1.0.7
            ├─geojson-utils
            │  └─1.0.4
            ├─hot-code-push
            │  └─1.0.0
            ├─html-tools
            │  └─1.0.5
            ├─htmljs
            │  └─1.0.5
            ├─http
            │  └─1.1.1
            ├─id-map
            │  └─1.0.4
            ├─insecure
            │  └─1.0.4
            ├─jquery
            │  └─1.11.4
            ├─launch-screen
            │  └─1.0.4
            ├─livedata
            │  └─1.0.15
            ├─logging
            │  └─1.0.8
            ├─meteor
            │  └─1.1.9
            ├─meteor-base
            │  └─1.0.1
            ├─minifiers
            │  └─1.1.7
            ├─minimongo
            │  └─1.0.10
            ├─mobile-experience
            │  └─1.0.1
            ├─mobile-status-bar
            │  └─1.0.6
            ├─mongo
            │  └─1.1.2
            ├─mongo-id
            │  └─1.0.1
            ├─npm-mongo
            │  └─1.4.39_1
            ├─observe-sequence
            │  └─1.0.7
            ├─ordered-dict
            │  └─1.0.4
            ├─promise
            │  └─0.5.0
            ├─random
            │  └─1.0.4
            ├─reactive-dict
            │  └─1.1.2
            ├─reactive-var
            │  └─1.0.6
            ├─reload
            │  └─1.1.4
            ├─retry
            │  └─1.0.4
            ├─routepolicy
            │  └─1.0.6
            ├─session
            │  └─1.1.1
            ├─spacebars
            │  └─1.0.7
            ├─spacebars-compiler
            │  └─1.0.7
            ├─standard-minifiers
            │  └─1.0.1
            ├─templating
            │  └─1.1.4
            ├─templating-tools
            │  └─1.0.0
            ├─tracker
            │  └─1.0.9
            ├─ui
            │  └─1.0.8
            ├─underscore
            │  └─1.0.4
            ├─url
            │  └─1.0.5
            ├─webapp
            │  └─1.2.2
            └─webapp-hashing
                └─1.0.5
```

#### パッケージ

[The trusted source for JavaScript packages, Meteor resources and tools &#124; Atmosphere] (https://atmospherejs.com/)

```text:packages
# Meteor packages used by this project, one per line.
# Check this file (and the other files in this directory) into your repository.
#
# 'meteor add' and 'meteor remove' will edit this file for you,
# but you can also edit it by hand.

meteor-base             # Packages every Meteor app needs to have
mobile-experience       # Packages for a great mobile UX
mongo                   # The database Meteor supports right now
blaze-html-templates    # Compile .html files into Meteor Blaze views
session                 # Client-side reactive dictionary for your app
jquery                  # Helpful client-side library
tracker                 # Meteor's client-side reactive programming library

standard-minifiers      # JS/CSS minifiers run for production mode
es5-shim                # ECMAScript 5 compatibility for older browsers.
ecmascript              # Enable ECMAScript2015+ syntax in app code

autopublish             # Publish all data to the clients (for prototyping)
insecure                # Allow all DB writes from clients (for prototyping)
```

##### [mongo] (https://atmospherejs.com/meteor/mongo)

> The mongo package is a full stack database driver

* Meteor.Collection.ObjectID()


##### [blaze-html-templates] (https://github.com/meteor/meteor/tree/devel/packages/blaze-html-templates)

> A meta-package that includes everything you need to compile and run Meteor templates with Spacebars and Blaze.

* [Spacebars] (https://atmospherejs.com/meteor/spacebars)
* [Blaze] (https://atmospherejs.com/meteor/blaze)

##### [session] (https://atmospherejs.com/meteor/session)

> This package provide Session. Session is a special ReactiveDict whose contents are preserved across Hot Code Push.

##### [jquery] (https://atmospherejs.com/meteor/jquery)

> jQuery is a fast and concise JavaScript Library that simplifies HTML document traversing, event handling, animating, and Ajax interactions for rapid web development.

##### [tracker] (https://atmospherejs.com/meteor/tracker)

> Meteor Tracker is an incredibly tiny (~1k) but incredibly powerful library for transparent reactive programming in JavaScript. (It was previously called Deps.)


#### パッケージの追加

```bat
> meteor add accounts-ui accounts-password
```

##### [accounts-ui] (https://atmospherejs.com/meteor/accounts-ui)

> A turn-key user interface for Meteor Accounts.



### meteor.bat

**where**

```bat:where
> where meteor
C:\Users\%USERNAME%\AppData\Local\.meteor\meteor.bat
```

**version**

```bat:version
> meteor --version
Meteor 1.2.0.2
```

**Usage**

```bat:usage
> meteor --help
Usage: meteor [--release <release>] [--help] <command> [args]
       meteor help <command>
       meteor [--version] [--arch]

With no arguments, 'meteor' runs the project in the current
directory in local development mode. You can run it from the root
directory of the project or from any subdirectory.

Use 'meteor create <path>' to create a new Meteor project.

Commands:
   run                [default] Run this project in local development mode.
   debug              Run the project, but suspend the server process for debugging.
   create             Create a new project.
   update             Upgrade this project's dependencies to their latest versions.
   add                Add a package to this project.
   remove             Remove a package from this project.
   list               List the packages explicitly used by your project.
   add-platform       Add a platform to this project.
   remove-platform    Remove a platform from this project.
   list-platforms     List the platforms added to your project.
   build              Build this project for all platforms.
   lint               Build this project and run the linters printing all errors and warnings.
   shell              Launch a Node REPL for interactively evaluating server-side code.
   mongo              Connect to the Mongo database for the specified site.
   reset              Reset the project state. Erases the local database.
   deploy             Deploy this project to Meteor.
   logs               Show logs for specified site.
   authorized         View or change authorized users and organizations for a site.
   claim              Claim a site deployed with an old Meteor version.
   login              Log in to your Meteor developer account.
   logout             Log out of your Meteor developer account.
   whoami             Prints the username of your Meteor developer account.
   test-packages      Test one or more packages.
   admin              Administrative commands.
   list-sites         List sites for which you are authorized.
   publish-release    Publish a new meteor release to the package server.
   publish            Publish a new version of a package to the package server.
   publish-for-arch   Builds an already-published package for a new platform.
   search             Search through the package server database.
   show               Show detailed information about a release or package.

See 'meteor help <command>' for details on a command.
```

#### create

利用できるExampleテンプレートを表示する

```bat:create
> meteor create --list
Available examples:
  clock
  leaderboard
  localmarket
  simple-todos
  simple-todos-angular
  simple-todos-react
  todos
```

Exampleテンプレートを利用してアプリケーションの雛形を作成する

```bat:create
> meteor create --example todos my-todos
Created a new Meteor app in 'my-todos' (from 'todos' template).

To run your new app:
  cd my-todos
  meteor

If you are new to Meteor, try some of the learning resources here:
  https://www.meteor.com/learn
```

#### update

プロジェクトで使用しているパッケージのバージョンを更新する

```bat:update
> meteor update

Changes to your project's package version selections from updating the release:

autoupdate              upgraded from 1.2.3 to 1.2.4
check                   upgraded from 1.0.6 to 1.1.0
ddp-common              upgraded from 1.2.1 to 1.2.2
ddp-server              upgraded from 1.2.1 to 1.2.2
ecmascript              upgraded from 0.1.5 to 0.1.6
ecmascript-collections  removed from your project
ecmascript-runtime      added, version 0.2.6
es5-shim                upgraded from 4.1.13 to 4.1.14
meteor                  upgraded from 1.1.9 to 1.1.10
mongo                   upgraded from 1.1.2 to 1.1.3
promise                 upgraded from 0.5.0 to 0.5.1
random                  upgraded from 1.0.4 to 1.0.5
reactive-dict           upgraded from 1.1.2 to 1.1.3
standard-minifiers      upgraded from 1.0.1 to 1.0.2
templating              upgraded from 1.1.4 to 1.1.5
webapp                  upgraded from 1.2.2 to 1.2.3

mt-example: updated to Meteor 1.2.1.
Your top-level dependencies are at their latest compatible versions.
```

#### deploy

デプロイする

```bat
> meteor deploy rubytomato-todos.meteor.com
Deploying to rubytomato-todos.meteor.com.
Now serving at http://rubytomato-todos.meteor.com
```

デプロイしたアプリケーションを削除する

```bat
> meteor deploy rubytomato-todos.meteor.com --delete
```


#### login / logout / whoami

Meteorでアカウントの登録が必要

***login***

```bat
> meteor login
Username: <entry username>
Password: *******

Logged in as <entry username>. Thanks for being a Meteor developer!
```

***logout***

```bat
> meteor logout
Logged out.
```

***whoami***

ログイン中のアカウントを確認できる

```bat
> meteor whoami
<entry username>
```


#### nodeのバージョン

meteorにバンドルされているnodeのバージョンの調べ方

```bat
> cd C:\Users\%USERNAME%\AppData\Local\.meteor\packages\meteor-tool\1.1.9\mt-os.windows.x86_32\dev_bundle\bin
> node -v
v0.10.40
```

#### MongoDBのバージョン

meteorにバンドルされているMongoDBのバージョンの調べ方
開発中はこのMongoDBが使用される(現バージョンでは32bit)

```bat
> cd C:\Users\%USERNAME%\AppData\Local\.meteor\packages\meteor-tool\1.1.9\mt-os.windows.x86_32\dev_bundle\mongodb\bin
> mongod --version
db version v2.6.7
2015-11-03T00:52:16.335+0900 git version: a7d57ad27c382de82e9cb93bf983a80fd9ac9899
```

WindowsのタスクマネージャでMongoDBのプロセスを確認

```bat
C:\Users\%USERNAME%\AppData\Local\.meteor\packages\meteor-tool\1.1.9\mt-os.windows.x86_32\dev_bundle\mongodb\bin\mongod --bind_ip 127.0.0.1 --smallfiles --port 3001 --dbpath D:\dev\meteor_workspace\mt-example\.meteor\local\db --oplogSize 8 --replSet meteor
```



### Meteor API

#### Templates

> In Meteor, views are defined in templates. A template is a snippet of HTML that can include dynamic data. You can also interact with your templates from JavaScript code to insert data and listen to events.

##### helpers

***Old***

古い記述方法

```js
Template.task1.tasks = function() {
  return [
    { text: "This is task.", no:1 },
    { text: "This is task.", no:2 },
    { text: "This is task.", no:3 },
    { text: "This is task.", no:4 }
  ];
}
```

***New***

```js
Template.task1.helpers({
  tasks: [
    { text: "This is task.", no:1 },
    { text: "This is task.", no:2 },
    { text: "This is task.", no:3 },
    { text: "This is task.", no:4 }
  ]
});
```

古い記述法を使用しているとchromeのコンソールに警告が表示されます。

```text
Warning: Assigning helper with `Template.task1.tasks = ...` is deprecated.  Use `Template.task1.helpers(...)` instead.
```


#### Session

> Session provides a global object on the client that you can use to store an arbitrary set of key-value pairs. Use it to store things like the currently selected item in a list.

#### Tracker

> Meteor has a simple dependency tracking system which allows it to automatically rerun templates and other functions whenever Session variables, database queries, and other data sources change.

#### Collections

> Meteor stores data in collections. JavaScript objects stored in collections are called documents. To get started, declare a collection with new Mongo.Collection.

#### Accounts

> To get accounts functionality, add one or more of the following packages to your app with meteor add:
> * accounts-ui
> * accounts-password
> * accounts-facebook, accounts-google, accounts-github, accounts-twitter

#### Methods

> Methods are server functions that can be called from the client. They are useful in situations where you want to do something more complicated than insert, update or remove, or when you need to do data validation that is difficult to achieve with just allow and deny.

#### Publish and subscribe

> Meteor servers can publish sets of documents with Meteor.publish, and clients can subscribe to those publications with Meteor.subscribe.

#### Environment

* Meteor.isClient
* Meteor.isServer
* Meteor.startup(func)

#### Packages

> All of Meteor's functionality is implemented in modular packages. In addition to the core packages documented above, there are many others that you can add to your app to enable useful functionality.

* add
 * Add a package to this project.
* remove
 * Remove a package from this project.
* search
 * Search through the package server database.


**show**

```bat:show
> meteor show mongo
Package: mongo@1.1.2
Maintainers: mdg
Exports: Mongo, MongoInternals (server)

The `mongo` package is a [full stack database
driver](https://www.meteor.com/full-stack-db-drivers) that provides
several paramount pieces of functionality to work with MongoDB in
Meteor:

- an efficient [Livequery][livequery] implementation providing real-time
updates from the database by consuming the MongoDB replication log
- a fall-back Livequery implementation for cases when the replication log is not
available, implemented by polling the database
- DDP RPC end-points for updating the data from clients connected over the wire
- Serialization and deserialization of updates to the DDP format

To learn more about Livequery, see the [project page on
www.meteor.com][livequery].

[livequery]: https://www.meteor.com/livequery

Recent versions:
  1.0.10  December 20th, 2014
  1.0.11  December 23rd, 2014
  1.1.0   March 18th, 2015
  1.1.1   September 22nd, 2015
  1.1.2   September 29th, 2015  installed

Older and pre-release versions of mongo have been hidden. To see all 73 versions, run 'meteor show --show-all mongo'.
```

### settings.json

API keyやクレデンシャル情報などを格納するのに使用される設定ファイルです。
アプリケーションのルートディレクトリに配置します。

* clientからはpublicに定義するキーが参照できます。
* serverからは全てのキーが参照できます。

```json:settings.json
{
  "public": {
    "client_key": "client_value"
  },
  "private": {
    "server_key": "server_value"
  },
  "key1": "value1",
  "custom": {
    "key2": "value2"
  }
}
```

実行時に読み込むjsonファイルを指定します。

```bat
> meteor --settings settings.json
```

サーバー

```js:server
var sv = Meteor.settings.private.server_key;
console.log(sv);
// ⇒ server_value
var cv = Meteor.settings.public.client_key;
console.log(cv);
// ⇒ client_value
var value1 = Meteor.settings.key1;
console.log(value1);
// ⇒ value1
var value2 = Meteor.settings.custom.key2;
console.log(value2);
// ⇒ value1
```

クライアント

```js:client
var sv = Meteor.settings.private.server_key;
console.log(sv);
// ⇒ エラー 
var cv = Meteor.settings.public.client_key;
console.log(cv);
// ⇒ client_value
var value1 = Meteor.settings.key1;
console.log(value1);
// ⇒ undefined
var value2 = Meteor.settings.custom.key2;
console.log(value2);
// ⇒ エラー
```

### 任意のMongoDBを利用する

MONGO_URL環境変数を定義します。
MONGO_URLの形式は`mongodb://<user>:<password>@<host>:<port>/<dbname>`です。

```bat
> MONGO_URL=mongodb://test_user:test_pass@localhost:27017/test_db
```

その後に通常通りアプリケーションを起動します。

```bat
> meteor
```

### ATOM plugin

* [meteor-api] (https://atom.io/packages/meteor-api)
* [meteor-helper] (https://atom.io/packages/meteor-helper)