Meteor入門(3)スマホでもキレイな簡単チャット

トップページにもサンプルへのリンクを貼っていますが、
そちらのchatのソースコードを掲載しておきます。
基本的には前回のマスタメンテと変わっていません。少し形を整えたのと、
スマートフォンでもキレイに見れるようにjQueryMobileを利用しているくらいです。

webchat.html

<head>
  <title>webchat</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.css" />
  <script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
  <script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.js"></script>
</head>

<body>
	  {{> editview}}
	  {{> listview}}
</body>

<template name="editview">
<div data-role="header">
<input type="button" id="delete" name="delete" value="履歴削除"> easy chat 
</div>
<div data-role="content">
  <table>
	  <tr>
		  <th>
		    <label>名前</label>
		  </th>
		  <td>
		    <input type="text" id="contributor" name="contributor" size="40" style="ime-mode: disabled;">
		  </td>
	  </tr>
	  <tr>
		  <th>
		    <label>内容</label>
		  </th>
		  <td>
		    <textarea id="voice" name="voice" rows="" cols="40"></textarea>
			  <input type="button" id="mention" name="mention" value="発言"><br>
		  </td>
	  </tr>
  </table>
</template>

<template name="listview">
	<table border="0">
	{{#each logList}}
	{{> log }}
	{{/each}}
	</table>
</div>
<div data-role="footer">

</div>
</template>

<template name="log">
<tr>
	<td>
	{{contributor}}
	</td>
	<td>
	=>
	</td>
	<td>
	{{voice}}
	</td>
	<td>
	({{date}})
	</td>
</tr>
</template>

webchat.js

//チャット履歴を作成
LogList = new Meteor.Collection("loglist");

//クライアント側処理
if (Meteor.isClient) {
 //登録部
  Template.editview.events({
    'click #mention' : function(){
        var date = new Date();
        //ここはちゃんとフォーマットライブラリを使おう
        var dateStr =  (eval(date.getMonth()) + 1) + "/" + date.getDate() +
         " " + date.getHours() + ":" + date.getMinutes() + ":" +  
         date.getSeconds();
        var log =  {contributor : jQuery("#contributor").val(),
                    voice : jQuery("#voice").val(),
                    date : dateStr, time : date.getTime()};
    
        LogList.insert({contributor:log.contributor, voice:log.voice, 
                        date:log.date, time:log.time});
        jQuery("#voice").val("");
    },
    'click #delete' : function(){
        LogList.remove({});
    }
  });
  
  //リスト部
  Template.listview.events({
    
  });
  
  Template.listview.logList = function(){
    //mteorでlimitは未実装?使えない。メテオなのにリミットブレイクが使えない...
    return LogList.find({}, {sort: {time: -1}});
  }
  
}


//サーバ側処理
if (Meteor.isServer) {

  Meteor.startup(function () {
    
  });
  
}

次回はこれにセッション管理を追加していきます。

Meteor入門(2)MongoDBの使い方

Meteor入門の第二回はサーバサイドのデータ保存であるMongoDBを使ってみたいと思います。
私の場合はMeteor初心者かつMongoDB初心者なので簡単なマスタメンテ作りながら
CLADの中でMongoDBのコマンドを覚えました。

簡単な概要はmeteor公式ドキュメントにも
記載されていますが、詳細な内容は当然MongoDB公式マニュアルを読んだ方が良いです。
(meteor側にも詳細はMongoDBのリファレンスを…と記載されています。)
※いくつかmeteor経由だとエラーになる関数があったので注意してください!取得数を制御するlimitとか…

簡単にRDBのSQLとの対比だけ言いますと、

  • select   → find
  • insert   → insert
  • update    → update
  • delete      →    remove

となっており、いづれも簡単な配列で検索クエリやオプションを渡すだけです。

MongoDBはクライアント操作がリアルタイムでMongoDBに反映され、全ユーザに伝播されます。
流れで言うと、
ユーザAがDB操作→ローカルデータ(miniMogo)を変更→サーバサイドのMongoDBを変更→
各ユーザのローカルデータ(miniMngo)を同期→pushで各ユーザのブラウザにリロードを要求
となります。(これはまた後ほど図に起こします。)

今回はソースを見た方が早いと思うので下にhtmlとjsのソースコードを全て載せておきます。

一点、MongoDBとは直接関係なくハマったのが、前回にテンプレートエンジンのバインドは
{{> テンプレート名}}と記述すると掲載しました。
これは間違っていないのですがバインドがネストしてその最終階層でbeanデータから
各プロパティをバインドする場合は{{変数名}}となります。
(以下の例で言うとitemテンプレートのcodeとname)

itemlist.html

<head>
  <title>chat</title>
</head>

<body>
  {{> editview}}
  <hr>
  {{> listview}}
</body>

<template name="editview">
  <input type="button" id="save" name="save" value="登録"><br>
  <table>
	  <tr>
		  <th>
		    <label>商品コード</label>
		  </th>
		  <td>
		    <input type="text" id="item-code" name="item-code" size="40" style="ime-mode: disabled;">
		  </td>
	  </tr>
	  <tr>
		  <th>
		    <label>商品名称</label>
		  </th>
		  <td>
		    <textarea id="item-name" name="item-name" rows="4" cols="40"></textarea>
		  </td>
	  </tr>
  </table>
</template>

<template name="listview">
	<b><label>商品一覧</label></b>
	<table border="1">
		<tr>
			<th>
				<label>商品コード</label>
			</th>
			<td>
				<label>商品名称</label>
			</td>
		</tr>
	{{#each itemList}}
	{{> item }}
	{{/each}}
	</table>
	<input type="button" id="delete" name="delete" value="全件削除">
</template>

<template name="item">
<tr>
	<th>
		{{code}}
	</th>
	<td>
		{{name}}
	</td>
</tr>
</template>

itemlist.js

//全商品のリストを作成
ItemList = new Meteor.Collection("itemlist");

//既存の商品リストとのバリデーション
ItemList.validate = function(item){
    if(item.code == null || item.code == ""){
        return false;
    }
    return true;
}

//クライアント側処理
if (Meteor.isClient) {

 //登録部
  Template.editview.events({
    'click #save' : function(){
        var item = {code : jQuery("#item-code").val(),
                    name : jQuery("#item-name").val()};
    
        if(!ItemList.validate(item)){
            alert("---- no item code ----");
            return;
        }
        var dbData = ItemList.findOne({code:item.code});
        //同一コードの存在チェック
        //存在すれば商品名をupdate、無ければinsert
        if(dbData != null){
            ItemList.update({code:item.code}, {$set: {name:item.name}});
        }else{
            ItemList.insert({code:item.code, name:item.name});
        }
    }
  });
  
  //リスト部
  Template.listview.events({
    'click #delete' : function(){
        ItemList.remove({});
        alert("---- all items were deleted ----");
    }
  });
  
  Template.listview.itemList = function(){
    return ItemList.find({});
  }
  
}


//サーバ側処理
if (Meteor.isServer) {

  Meteor.startup(function () {

  });
  
}