SI屋的(?)JavaScript(jQuery)活用方法

SI屋的なWebシステムの開発において、どこまでJavaScriptを使うのかについては、いくつかパターンがあると思うわけですが。

1. 機能要件では無いし、お金にならないのでいっさい使わないパターン(´д`;)
2. jQueryとdata属性なんかを使えば、宣言的にそれなりに装飾されたものをコストをかけずに作れるので、そのパターン(・ω・)
3. フルJavaScript…っというか、MVVMライブラリを使うだけで無く、GWTみたいなものを使わないとやる気が起きないパターン(・∀・;)

っで、未だに1のパターンも多かったりする一方で、jQueryの登場以降、使い方を考慮することで、SI屋的なシステムでもコストをかけずにUIをリッチにすることも可能になってきたので、その方法について書きたいと思います(`・ω・´)

そもそも

SI屋的なシステム開発における統制の観点から言うと、JavaScriptの記述は他のロジック記述に比べて個人差が出るので*1、担当者個々に処理を書かせたくないという話があるかと思います(´д`;)
また、各html(jsp、aspx)ページ内にJavaScriptの記述が混在すると、メンテナンス的に好ましくないという懸念もあるかと思います。


今回提唱する方法は、上記懸念に対する一定の回答を示しながら、JavaScriptを活用してUIをそれなりにリッチにする方法だと思います(・ω・)
その方法とは、簡単に言えば「data属性の活用と宣言的な記述」です。


なお、以降はjQuery前提での話となります。

data属性

data属性とはなんぞや?、っという人にはググって貰うとして(・∀・;)
要は、data属性を用いて、html内には処理(JavaScript)に必要なパラメータのみを記述することで、htmlからJavaScriptの完全分離をしようというのが今回提唱する案の肝になります。


簡単な例として言えば、

宣言的記述

動作を書くのでは無く、それが何をするものであり、必要なパラメータは○○であるということをに記述することで、処理(JavaScript)とhtmlを分離することが出来ます。
その場合、処理(JavaScript)の方はどう書くのかという話になりますが、まず、基本の考え方としては以下の様になります。

  • 特定のコンテキスト(id、class、タグの親子関係等)に対して適用する
  • プラグイン/ライブラリというレベルでの共通化とは別に、アプリケーション固有のコンテキストに適用する層を用意する

…っと言ってもよく分からない(´д`;)と思うので、前述の

処理パターン

コンテキスト適用層は処理毎に分離して、画面毎に必要なものをインクルードする形でメンテナンスしやすくすることが出来ます。
っということで、以下、処理パターン毎に分離する時の例をいくつか書いてみます。

非同期ロード(asyncload.js)

ポータル的な画面などで複数Widget的な要素を配置して、それを非同期にロードして見せたいような場合の処理の例です。

$(document).ready(function() {
    $(".asyncload").each(function(index, e) {
        var $this = $(e);
        $.ajax({
            type: "GET",
            url: $this.data("url"),
            context: $this,
            success: function(data, textStatus, xhr) {
                $(this).empty().append(data);
            },
            error: function() {
            },
            complete: function() {
            },
            dataType: "html"
        });
    });
});

[class=asyncload]のコンテキストに対して、data-urlから表示する先のURLを取得し、それのhtmlを非同期に取得して画面を更新する、っという処理です。
この場合の適用コンテキストの例としては、下記の様になります。

<div id="weatherWidget" class="asyncload" data-url="/widget/weather">
<img src="/images/loading.gif"/>
</div>

画面の実装者は上記の様なhtmlを記述するだけでよくなり、htmlとJavaScriptの分離、もとい、個々の画面担当者とJavaScript担当者という形での作業の分離が(SI屋的に)出来るようになります(・∀・;)

パーシャルアップデート(partial.js)

もう少し複雑なパターンとして、部分更新(ASP.NETにおけるUpdatePanel的なもの)の処理例を書いてみます。

$(document).ready(function() {
    var partialUpdate = function(e, name) {
        var form = e.parents("form");

        var url = e.data("url");
        if (!url) {
            url = form.attr("action");
        }

        var target = e.data("target");
        if (!target) {
            target = form.data("target");
        }

        var data = form.serializeArray();
        data.push({ name: "_partial", value: name });

        $.ajax({
            type: "POST",
            url: url,
            data: data,
            context: target,
            success: function(data, textStatus, xhr) {
                $(this).empty().append(data);
            },
            error: function() {
            },
            complete: function() {
            },
            dataType: "html"
        });
    };

    $("select.partial").live("change", function() {
        var $this = $(this);
        partialUpdate($this, $this.attr("name"));
    });

    $("input[type='button'].partial").live("click", function() {
        var $this = $(this);
        partialUpdate($this, $this.attr("name"));
    });

    $("a.partial").live("click", function() {
        var $this = $(this);
        var name = $this.attr("href")
        if (name.indexOf("#") == 0) {
            name = name.slice(1);
        }
        partialUpdate($this, name);
        return false;
    });
});

解説の前にhtmlも。

<div id="updatePanel">

<form action="/partial" method="POST" data-target="#updatePanel">

<input type="text" name="data1" value=""/>

<select name="data2" class="partial">
<option value="1">データ1</option>
<option value="2">データ2</option>
<option value="3">データ3</option>
</select>

<input type="button" name="trigger" value="トリガー" class="partial"/>

<a href="#link" class="partial">パーシャルリンク</a>

<input type="submit" value="更新"/>

</form>

</div>

この例は、[class=partial]なselect、button、リンクに対する操作に対して、formのaction先にAjaxでデータをPOSTする(応答では

内を返して貰う)ことにより、画面全体の更新無しで、同じ画面(from)の値を書き換えながら処理を行うという、ASP.NETにおけるUpdatePanel的な処理を実現するものです。
サーバ側のハンドラでは、_partialパラメータがdata2、trigger、link及び無しの何れかを判別することで、どの要素による部分更新なのか、あるいはsubmit処理なのかを判別できます。


画面担当者は、上記のルールに従って実装すれば、後は既存の作りと変わらずにAjax的なformを作れるようになる、っと言うわけです(・ω・)

まとめ

data属性と宣言的な記述により、htmlとJavaScriptの完全分離が出来るようになりました(・∀・)
また、このことによりJavaScriptの実装は少数のコンテキスト適用層を作る人に任せることが出来るようになりました。


っということで、SI屋的な開発でも、コストをあまりかけず、品質面での統制も問題無く、Ajax/JavaScriptを使ったそれなりにリッチなWebシステム開発が出来るようになりますね、っという話ですが、どうでしょう(・ω・)?

おまけ

自分の出自はWindowsプログラマ〜バックエンド/サーバ側なので、JavaScript自体それほど好きというわけでも無いですが、なんだかんだ言いつつ、去年はJSのコードを結構書いていたたり、本も読んだりしたので、これも時代でしょうかね(・ω・)?

コアjQuery+プラグイン/jQuery UI 開発実践技法 (Programmer’s SELECTION)

コアjQuery+プラグイン/jQuery UI 開発実践技法 (Programmer’s SELECTION)

ちなみにこれ、jQuery in Actionの邦訳ね。*2


っで、SI屋的なWebシステム開発におけるJavaScriptの課題としては、自分としては以下のようなものが残っていると思っています。

  • JavaScriptコードの静的テストツール、及びCIとの組み合わせ
  • jQueryはデフォとして、ユーティリティ、オブジェクトクエリ、バインディング*3、モバイル(スマフォ対応)、テストあたりは何かしらライブラリを使用することになると思うので、自分達なりのそのセットの評価とメンテ

*1:正しくは、Controller/ServiceやSQLのコピペバインダー的な作業よりも、UI制御の記述の方が頭を使う、という意味だと思いますが(・∀・;)

*2:余談だけど、元がin Actionシリーズの邦訳だっていうのが分かりにくい書籍が最近多いよね(・∀・;)

*3:単純にMVxパターンのJS版というだけでなく、サーバコードからの自動生成/自動連携的なものも欲しい、っというのは贅沢ですか(・∀・)?