読者です 読者をやめる 読者になる 読者になる

arinoth's memo

arinothのメモ

Meteorで非公開ツール用のログインフォームを作る(その3)

前回テンプレートの再レンダリングを避けてjQueryで表示/非表示をするインターフェースにしましたが、 考えてみると部分的とはいえMeteorで再レンダリングを避けると長所をつぶすようなものだし、 そもそもユーザー作成を折りたたみUIにする意味があまりないので、 ダイアログボックスを使ったインターフェースに変更します。

f:id:arinoth:20140118230004p:plain

jQuery UIでダイアログボックスを表示

手軽にダイアログボックスを作るためにまずjQuery UIを導入。 といってもダウンロードしたファイルをclientフォルダに入れておけば完了。

f:id:arinoth:20140118220208p:plain

Meteorはアルファベット順(ASCII順?)にファイルを自動的に読み込んでくれるので、読み込み順を変えたいときはファイル名を変えるのだそうです。 今回はたまたま「j」よりも後のファイル名しか使っていなかったのでそのままでOK。

ログインコントロールのテンプレートを修正して、テンプレート関数usercreateで表示/非表示を切り替える形式にして……

client/logging.html

<template name="logincontrol">
    <ul>
        <li><a id="logout">ログアウト</a></li>
        {{#if superuser}}
        <li><a id="link_usercreate">新規ユーザー作成</a></li>
        <li><a id="link_usermanage">ユーザー管理</a></li>
        <div>管理画面</div>
            {{#if usercreate}}
                {{> createuserform}}
            {{/if}}
            {{#if usermanage}}
                管理画面
            {{/if}}
        {{/if}}
    </ul>
</template>

ユーザー作成フォームのdiv要素にidを付けて……

<template name="createuserform">
    <div class="form-horizontal" role="form" id="dialog_createuser">
        <dl>
            <dt>UserName(半角英数)</dt>

ユーザー作成フォームがレンダリングされたら、自動的にdialog化するコードを書き、

crient/logging.js

//ユーザー作成フォームの警告を隠す
Template.createuserform.rendered = function () {
    $('#dialog_createuser').dialog({ autoOpen: true });
    $('.alert').hide();
   //最初のユーザー作成時はスーパーユーザーにデフォルトでチェック
    if(Session.get('firstuser')){
        $('#chk_superuser').prop('checked', true);
    }
};

最後に表示/非表示を切り替えるセッション変数とテンプレート関数を定義。

//隠しコントロールの表示/非表示
Template.logincontrol.events({
    'click #link_usercreate': function (event) {
        Session.set('usercreate', true);
    }
});
Template.logincontrol.usercreate = function(){
    return Session.get('usercreate');
}

これでとりあえずダイアログ表示できるようになりました。

f:id:arinoth:20140118220220p:plain

ただ、これだとユーザーダイアログを閉じた後、再表示ができません。

セッション変数がtrueに書き変わるのをダイアログ表示のトリガーにしているので、 jQuery UIの機能で非表示にしてもセッション変数がtrueのママになってしまい、次回書き換えが発生しません。

なので、jQuery UIのdialogにもう少しちゃんとパラメータを設定し、 閉じたときにセッション変数にfalseを代入するようにします。ついでにモーダルにしてタイトルも設定。

//ユーザー作成フォームの警告を隠す
Template.createuserform.rendered = function () {
    $('#dialog_createuser').dialog({
        title: 'Create User',
        autoOpen: true,
        modal: true,
        close: function( event, ui ) {Session.set('usercreate', false);}
    });
    $('.alert').hide();
   //最初のユーザー作成時はスーパーユーザーにデフォルトでチェック
    if(Session.get('firstuser')){
        $('#chk_superuser').prop('checked', true);
    }
};

これでOKです。

f:id:arinoth:20140118220231p:plain

ちょっと流れがややこしいので整理すると……


  1. テンプレートlogincontrolの#link_usercreateがクリックされる
  2. クリックイベントを補足してセッション変数usercreateにtrueをセット
  3. セッション変数usercreateを参照しているテンプレート関数usercreateがtrueを返す
  4. テンプレート内の{{#if usercreate}}が反応して、テンプレートcreateuserformがレンダリングされる
  5. Template.createuserform.renderdの中のdialogが実行されダイアログ化される

ダイアログボックスの表示/非表示はjQuery UIでもできますが、ユーザー作成はそう頻繁に使うものではないですし、 次に作るユーザー管理画面はMeteorの自動同期をバリバリ使ってみるつもりなので、 使わないときはHTMLごと消してしまうほうが軽くていいんじゃないかと思ってこうしてみました。

しかし、結構がらっとUIを変えたのに、ユーザー作成の処理そのものはまったく変更不要なのがすごいですね。 テンプレートごとにコードが分かれているおかげでしょうか。

よく見るとjQuery UIの画像が読み込まれてない……!?

ここで気がついたのですが、閉じるボタンのバッテンマークなど、jQuery UIの画像が読み込まれていません。

そういえば画像はpublicフォルダの中に入れるという説明があったような……。

色々試行錯誤した結果、CSSはclientフォルダに入れたままにして、 画像はpublicフォルダの中にそれを読み込むCSSと同じパスになるようフォルダを作って入れればいいようです。

今回の場合、CSSのパスはclient/jquery-ui-1.10.3.custom/css/excite-bike/jquery-ui-1.10.3.custom.min.cssなので、 画像はこうなることになります。

f:id:arinoth:20140118225922p:plain

なんか面倒なのでホントかいなという気もするんですが……。パスをもっと短いものにリネームすればたいした問題ではないですかね?

f:id:arinoth:20140118230004p:plain

ここまでの成果(ZIP)

追記

jQuery UIのdialogは色々要素を挿入するので、今回の方式だとダイアログを閉じるときにdestroyしないとHTMLがゴミだらけになります。

//レンダリング時
Template.createuserform.rendered = function () {
    $('#dialog_createuser').dialog({
        title: 'Create User',
        autoOpen: true,
        modal: true,
        close: function( event, ui ) {
            Session.set('usercreate', false);
            $('#dialog_createuser').dialog('destroy');  //ちゃんとデストロイ!
        }
    });
……後略……