日本が取るべき「ガラパゴス戦略」
1つめの封筒を開けたStephen Elop (CEO of Nokia)

SNBinder入門:一行おきに背景色を変えるテクニック

ピュアAjaxアーキテクチャ」なウェブサイトを実現するために作ったSNBinder、多くの方々からフィードバックをいただけ、私もとても良い勉強になっている。そんなフィードバックの中に、「テンプレート内で条件分岐ができるようにして欲しい」「テンプレート内にスクリプトが書ける様にして欲しい」などのリクエストをたびたび見かけるので、今日はそれに関してひと言。

たしかに、従来型のテンプレートのほとんどに「繰り返し」や「条件分岐」の機能がある。ものによっては、そのテンプレート中にスクリプトが書けてしまうものもある。SNBinderにそんな機能を追加するのもけっして難しくないのだが、私がSNBinderで実現しようとしている方向性とは少し違う、と感じている。

そもそもテンプレートとは、JavaとかPythonなどで記述された「ロジック(もしくはコントローラ)」と、ユーザーに何を見せるかというHTML(ビュー)を切り離すことにより、メンテナンスをしやすくしようという試みである。

しかし、それを「特定のURLにリクエストが来ると、サーバー側でHTMLページを生成して返す」という従来型のアーキテクチャにはめ込もうとすると、どうしてもテンプレート側に「繰り返し」や「条件分岐」の機能を追加せざるをえない。返すべきページを一つのテンプレートで表現し、その中に「リスト」を表示したり、特定の条件に応じて何かを表示する必要があるからだ。ロジックとビューを切り離すという発想から言えば本末転倒とも言えるが、ウェブのアーキテクチャ上しかたがないという面もあり広く用いられているテクニックだ。

SNBinderが前提にしている「ピュアAjaxアーキテクチャ」は、従来型のものとは大きく異なるアーキテクチャである。ブラウザーが最初にHTTP-GETで取得するHTMLページは静的ファイルであり、そこにJavaScriptでページを作るのに必要な部品を「名前付きテンプレートの集まり」としてを読み込み、サーバーのAPIを叩いてJSONを取得した上で、その取得したJSONと名前付きテンプレートの一つ(=部品)を結合(Bind)した上で、HTMLページの適切な場所にペタペタと「貼付ける」のだ。

この場合には当然だが、すでにさまざまなロジックをJavaScriptで記述しているわけで、「繰り返し」や「条件分岐」もJavaScriptでするのが自然であり、そうすることによってロジックとビューをきれいに切り離したままに保つことができる。

説明のために少し具体例を示そう。

「繰り返し」に関しては、bind_rowsetというヘルパー関数をもうけており、

            $('ul#completed_todos').html(SNBinder.bind_rowset(s_parts['todo_item'],json)); 

のような書き方が可能だが、これは

            var func = SNBinder.compile(s_parts['todo_item']);
            var rows = []; 
            for (var index in json) {
                rows.push(func(json[index], index));
            }
            $('ul#completed_todos').html(rows.join(''));

と同値である。

例えば、リストを表示する際に、1行おきに背景色を変えたい場合などは、偶数行・奇数行向けのテンプレートを二つ用意しておき、

            var func_even = SNBinder.compile(s_parts['todo_item_even']);
            var func_odd = SNBinder.compile(s_parts['todo_item_odd']);
            var rows = []; 
            for (var index in json) {
                if (index % 2==0) {
                    rows.push(func_even(json[index], index));
                } else {
                    rows.push(func_odd(json[index], index));
                }
            }
           $('ul#completed_todos').html(rows.join(''));

とすれば良い。JSONを変更してかまわないのであれば、

           for (var index in json) {
               json.css_class = (index % 2 ==0) ? 'even' : 'odd';
           }
           $('ul#completed_todos').html(SNBinder.bind_rowset(s_parts['todo_item'],json)); 

のようにあらかじめcss_classというプロパティを各行のデータに持たせておき、それをテンプレートで展開するという手法もある(Fruenceはこの手法を使っている)。

なぜこんなことが可能になるかというと、SNBinderであつかうテンプレートが「ページ全体を表したもの」ではなく、「データと結合した上でHTMLページに貼付けるべき部品」だからである。サーバー側でのテンプレートに慣れた人には少し発想の転換をしていただく必要があるが、その発想の転換さえしていただければ、SNBinderのテンプレートには「繰り返し」や「条件分岐」が必要ない、ことが理解していただけると思う。

Comments

Verify your Comment

Previewing your Comment

This is only a preview. Your comment has not yet been posted.

Working...
Your comment could not be posted. Error type:
Your comment has been posted. Post another comment

The letters and numbers you entered did not match the image. Please try again.

As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

Having trouble reading this image? View an alternate.

Working...

Post a comment

Your Information

(Name is required. Email address will not be displayed with the comment.)