Aptana JaxerでサーバサイドJavaScriptを始めてみよう!

第3回サンプルアプリ(タスク管理アプリ)作成 -タスクの登録・表示-

Jaxerアプリケーションの作成

前回は、Jaxerの環境構築、およびサンプルアプリの解説をしました。今回から、いよいよJaxerアプリケーションのプログラミングに取り掛かります。

今回作成するサンプルアプリケーションは、タスク管理アプリです。画面イメージは以下のようになります。

画面イメージ

実装する機能は、次のものになります。

  • テキスト入力欄にタスクを入力し、Enterキーを押すと、タスクが登録できる。
  • 登録したタスクは、即時画面上に反映される。
  • 既存のタスクをクリックすると、テキスト入力欄になり、タスクの内容を編集できる。
  • ×をクリックすると、タスクを削除できる。

それでは、前回インストールしているAptana Studioを起動しましょう。

起動後、以下の手順で、まずは「task」プロジェクトを作成します。

  1. project viewで右クリック→New→Projectを選択する。

  2. New Projcetウィンドウで、⁠Aptana Projects⁠⁠→⁠Default Web Project」を選択し「Next」をクリックする。

  3. Project name欄に、今回作成するアプリのフォルダ名を入力する。今回はサンプルアプリとして、タスク管理アプリを作成するので、"task"と入力して、⁠Next」をクリックする。

    今回作成するアプリのフォルダ名を入力する
  4. 続いて利用するJavaScript Libraryを選択する。今回は、jQueryを利用するので、jQueryのチェックボックスにチェックをつけて、⁠Next」をクリックする。

    jQueryのチェックボックスにチェック
  5. 「Include Jaxer sample in project」以外にチェックをつけて、⁠Next」をクリックする。

    「Include Jaxer sample in project」以外にチェック
  6. 最後は何も入力せず、そのまま「Finish」をクリックする。

これで、project view のところに以下のようなファイル構成でプロジェクトが作成されます。

プロジェクトが作成された

「jquery_sample.htm」「jquery_sample.js」は、jQueryのサンプルなので、削除しましょう。今回作成するページは、index.htmlなので、⁠task」プロジェクトを選択した状態で、右クリック→⁠New⁠⁠→⁠HTML file」を選択します。

「HTML file」を選択

表示されたウィンドウで、ファイル名欄にindex.htmlと入力して「Finish」をクリックします。

ファイル名欄に入力

するとproject viewにindex.htmlが現れ、中央のエディットエリアにindex.htmlのソースが表示されます。

index.htmlソースの表示

それでは、まず先ほどの画面イメージをHTMLで実装してみましょう。

ソースは以下のようになります。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type"
content="text/html; charset=utf-8" />
    <title>タスク管理</title>
    <style type="text/css">
      body {background-color:#FFFFE0}
      form {display:inline;margin:0px;}
      span.del_memo {cursor:pointer;font-weight:bold;}
    </style>
  </head>
  <body>
    <form name="add_form" id="addForm">
      <div><input type="text" size="50" name="new_task" id="newTask"/></div>
    </form>
    <div>
       <div><span class="del_memo">×</span><span class="memo">牛乳を買う</span></div>
       <div><span class="del_memo">×</span><span class="memo" >
         <form name="edit_form"><input name="edit_task" type="text" value="サンプルアプリを作る"/></form>
       </span></div>
    </div>
  </body>
</html>

テンプレートのままだとmetaタグのcharsetの値が「iso-8859-1」になっていますが、ファイル自体はAptana Studioフォルトの設定でutf-8で保存されているので、charsetの値を「utf-8」に変更しておきましょう。

JavaScriptやCSSは解説の便宜上、index.html内に記述していますが、外部ファイルにしてもかまいません。ただし、JavaScriptの外出しについては一部例外があるので、注意が必要です。この点については別の回で解説します。

次に、DBのテーブルを作成する以下のコードを、metaタグのすぐ後に書きます。

<script runat="server">
  var sql = "CREATE TABLE IF NOT EXISTS memo " +
    "( id INTEGER PRIMARY KEY AUTO_INCREMENT" +
    ", contents TEXT NOT NULL" +
    ")";
  Jaxer.DB.execute(sql);
</script>

scriptタグのrunat属性がserverになっているので、この部分のコードはサーバサイドで実行されます。SQL文でテーブルのcreate文を作成し、Jaxer.DB.execute()でSQLを実行します。

この部分のコードは、ページが表示される毎に実行されます。

毎回DBでcreate文が実行されますが、SQL文の「IF NOT EXISTS memo」の部分にあるように、すでにmemoテーブルが存在する場合はcreate tableは実行されません。

とはいえ、意味のないSQL文が頻繁に実行されるのはよろしくないので、Jaxer付属のchatアプリのコードを参考にして、上記コードを以下のように書き換えます。

<script runat="server">
  (function(){
    if (Jaxer.application.get("isInitialized")) return;
    var sql = "CREATE TABLE IF NOT EXISTS memo " +
      "( id INTEGER PRIMARY KEY AUTO_INCREMENT" +
      ", contents TEXT NOT NULL" + 
      ")";
    Jaxer.DB.execute(sql);
    Jaxer.application.set("isInitialized", true);
  })();
</script>

Jaxer.applicationはアプリケーション全体で値を共有できるAPIで、Jaxer.application.get(key)で値を取得し、Jaxer.application.set(kye,value)で値を保存します。

今回のコードでは、テーブルをcreateした後、"isInitialized"というkeyにtrueという値を保存し、次回のアクセス以降テーブル作成のSQLが実行されないようにしています。

次に、jQueryを読み込みましょう。この後、サーバサイド、クライアントサイド両方で使う予定なので、scriptタグのrunat属性をbothにした以下のコードを先ほどのscriptタグに続けて書きます。

<script src="lib/jquery/jquery.js" runat="both"></script>

これで、サーバサイド、クライアントサイドの両方で、jquery.jsが読み込まれ、jQueryが利用できるようになりました。

続いて、タスクを登録する部分を作ります。

jQueryを読み込んでいるscriptタグの次に、以下のようなコードを書きましょう。

<script runat="server-proxy">
  function add(task){
    try{
      task = decodeURIComponent(task);
      Jaxer.DB.execute("INSERT INTO memo (contents) VALUES (?)",task);
      return true;
    }catch(e){
      return false;
    }
  }
</script>
<script runat="client">
  $(init);
  function init(){
    $("#addForm").submit(function(){
      add(encodeURIComponent($('#newTask').val()));
      $('#newTask').val('');
      return false;
    });
  }
</script>

これで画面上の入力フォームでタスクを入力し、Enterを押下すると(Submitすると⁠⁠、DBへ登録することができます。

ポイントは、runat属性がserver-proxyとして定義されているaddメソッドをクライアントサイドでadd()として利用できているところです。

ただし、ブラウザからサーバ側へ通信が発生しているので、addメソッドに渡す引数は、encodeURIComponent()を利用してエンコードします。

もちろん、サーバサイドのaddメソッド内でdecodeURIComponent()でデコードするのを忘れずに行います。

ここまでで、DBへのタスクの登録ができたので、登録されているタスクを画面に表示しましょう。

addメソッドを定義しているscriptタグの中に、以下の関数を追加します。

function getAllTask(){
  var rs = Jaxer.DB.execute('SELECT * FROM memo');
  var html = '';
  for(var i = 0,len = rs.rowsAsArrays.length;i<len;i++){
    html += '<div><span class="del_memo">×</span><span class="memo" >'+
rs.rowsAsArrays[i][1]+'</span></div>';
  }
  return html;
}

memoテーブルをselectして、結果をResultSetで受け取り、ページに表示する形に整形して返します。

続いて、runat属性がbothのタグを追加し、以下のコードを追加します。

<script runat="both">
  function loadAllTask(){
    var html = getAllTask();
    $('#tasks').html(html);
  }
</script>

タスクを表示する部分のdivタグにid="tasks"を追加し、簡単にアクセスできるようにしておきます。

さらに、ページ表示時に、loadAllTask関数が実行されるように、bodyタグに onserverload="loadAllTask();"を追加します。

onserverload属性は、サーバ側でDOM操作の準備が完了した段階で実行する関数を指定できる属性になります。

ここまでの作業をまとめると、ソースは以下のようになります。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <script runat="server">
      (function(){
        if (Jaxer.application.get("isInitialized")) return;
        var sql = "CREATE TABLE IF NOT EXISTS memo " +
          "( id INTEGER PRIMARY KEY AUTO_INCREMENT" +
          ", contents TEXT NOT NULL" +
          ")";
        Jaxer.DB.execute(sql);
        Jaxer.application.set("isInitialized", true);
      })();
    </script>
    <script src="lib/jquery/jquery.js" runat="both"></script>
    <script runat="both">
      function loadAllTask(){
        var html = getAllTask();
        $('#tasks').html(html);
      }
    </script>
    <script runat="server-proxy">
      function getAllTask(){
        var rs = Jaxer.DB.execute('SELECT * FROM memo');
        var html = '';
        for(var i = 0,len = rs.rowsAsArrays.length;i<len;i++){
          html += '<div><span class="del_memo">×</span><span class="memo" >'+ rs.rowsAsArrays[i][1]+'</span></div>';
        }
        return html;
      }
      function add(task){
        try{
          task = decodeURIComponent(task);
          Jaxer.DB.execute("INSERT INTO memo (contents) VALUES (?)",task);
          return true;
        }catch(e){
          return false;
        }
      }
    </script>
    <script runat="client">
      $(init);
      function init(){
        $("#addForm").submit(function(){
          add(encodeURIComponent($('#newTask').val()));
          $('#newTask').val('');
          return false;
        });
      }
    </script>
    <title>タスク管理</title>
    <style type="text/css">
      body {background-color:#FFFFE0}
      form {display:inline;margin:0px;}
      span.del_memo {cursor:pointer;font-weight:bold;}
    </style>
  </head>
  <body onserverload="loadAllTask();">
    <form name="add_form" id="addForm">
      <div><input type="text" size="50" name="new_task" id="newTask"/></div>
    </form>
    <div id="tasks">
      <div><span class="del_memo">×</span><span class="memo">牛乳を買う</span></div>
      <div><span class="del_memo">×</span><span class="memo" >
        <form name="edit_form"><input name="edit_task" type="text" value="サンプルアプリを作る"/></form>
      </span></div>
    </div>
  </body>
</html>

では、実際にJaxerサーバで動かしてみましょう。Aptana Studioのメニューバー近くにあるJaxerボタンをクリックし、サーバを起動しましょう。

Jaxerボタン

Jaxerボタンの色が緑色になったら、エディタ下部のSourceタブをIEタブに切り替えてみましょう。まだDBにはタスクが1つも登録されていないので、以下のような画面になります。

1つも登録されていない画面

gatAllTask()の戻り値が空文字なので、loadAllTask()の中で、<div id="tasks">のinnerHTMLがクリアされています。では、タスクを入力してEnterを押下してみましょう。

テキストボックスの文字が消えたら、テキストボックスのsubmitイベントに紐付けられた関数が実行されたことになります。では、プレビューをしている状態でページのリロードボタンを押下してみましょう。

リロードボタン

すると、以下のように、先ほど入力したタスクが表示されると思います。

タスクが表示される

タスクを登録して、いちいち画面をリロードさせるのはいまいちなので、タスク登録時に現在登録しているタスクを全てサーバから取得するようにしてみましょう。

この作業はとても簡単です。init関数の中で、タスク登録欄のSubmit属性に紐付けている関数にgetAllTask()を追加するだけです。

  function init(){
    $("#addForm").submit(function(){
      add(encodeURIComponent($('#newTask').val()));
      $('#newTask').val('');
      loadAllTask();
      init();
      return false;
    });
  }

さあ、これで再度プレビュー画面でタスクを登録してみましょう。

今度は、タスクを登録すると画面をリロードしなくても、入力欄下のタスク一覧が更新されます。ポイントは、DBからデータを取得して画面を書き換えるロジックを作成する場合、DBアクセスする関数とDOMを操作する関数を分けるというところです。

Jaxerで実行されるJavaScriptのコードは大きく以下の3つに分けることができます。

  1. ページ表示前にサーバサイドで実行されるコード
  2. ページ表示後にクライアントサイドで実行されるコード
  3. ページ表示後にクライアントサイドからコールされ、サーバサイドで実行されるコード

この「3」にあたるサーバサイドで実行されるコードでは、DOM操作ができません。サーバサイドのJavaScriptでDOM操作ができるのがJaxerの魅力ですが、この点には注意しておきましょう。

今回は、タスク管理アプリのタスク登録まで作成しました。

次回は、入力値チェックの共有や、タスクの編集、削除の部分を作成したいと思います。

おすすめ記事

記事・ニュース一覧