Catalystでajax (HTML::Prototypeモジュールの使い方)

changelog

概要

Catalyst で作る簡単 Web アプリケーション: Feed2JS 解説を参考にしながら、Catalystをいじっていたのですが、ajaxな部分を司るCatalyst::Plugin::Prototypeについて調べたことを、ここにメモしておきます。

まず、「prototype」という名が示すのは、「原型」という意味ではなくて、prototypeという名のオブジェクト指向Javascriptライブラリです。俺は最初それが分からず、「ん?何かの原型を作るようなモジュールなのか?」と悩んでました。このライブラリの実態はこんな感じです。prototype.js

で、Catalyst::Plugin::Prototype自体は、HTML::PrototypeのメソッドをCatalystのビューから呼び出せる様にするものです。なので、Catalyst::Plugin::Prototypeの使い方を知るためには、まずはHTML::Prototypeの使い方を知る必要があります。

このHTML::Protoytypeは何をするものなのかというと、prototype.js内のajax関連の関数を呼び出すようなHTMLを手軽に生成するためのもの、ということになります。以下、HTML::Prototypeの使い方と、Catalystから呼び出す方法についてHTML::Prototypeのドキュメントを参考にしながら、実行例も交えて順に見ていきます。また、ドキュメントに載っていないものの、ソースコードから読みとれるものもできる限り記述したいと思います。

基本的なHTML::Prototypeの使い方は以下の様になります。

use HTML::Prototype;

my $prototype = HTML::Prototype->new;
print $prototype->define_javascript_functions;

HTML::Prototypeで利用できるメソッドは以下の通りです。

各メソッドを順に見ていきます。

$prototype->define_javascript_functions

このメソッドはprototype.jsの内容そのものを返します。つまり、

print $prototype->define_javascript_functions;

を実行すると、以下の内容が出力されます。

<script type="text/javascript">
<!--
/*  Prototype: an object-oriented Javascript library, version 1.2.0
 *  (c) 2005 Sam Stephenson <sam@conio.net>
 *
 *  THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff
 *  against the source tree, available from the Prototype darcs repository.
 *
 *  Prototype is freely distributable under the terms of an MIT-style license.
 *
 *  For details, see the Prototype web site: http://prototype.conio.net/
 *
/*--------------------------------------------------------------------------*/

var Prototype = {
  Version: '1.2.0'
}
... (省略)

これはあんまり使い道ない気がします。HTML内で、

<script type="text/javascript" src="prototype.js"></script>

としてやればいいですし、Catalystでも、

$ script/my-app_create.pl Prototype

でroot以下にprototype.jsが生成されますから。

$prototype->form_remote_tag(\%option)

このメソッドでは、xmlHttpRequestでサブミットする様なformタグを生成します。オプションとその説明は以下の通りです。

$prototype->form_remote_tag({
    method => 'post',
    url => '/url',
    update => 'id',
    position => 'Before',
    type => 'synchronous',
    callback => 'callback()',
});
method
リクエストメソッドを指定します。
url
submit先のURLを指定します。
update
xmlHttpRequestで得られたレスポンスを、どのidを持つコンテナに挿入するかを指定します。つまり、ここで指定したidに対して、prototype.jsが document.getElementById(id).innerHTML = req.responseText; みたいなことをやってくれます。
position
何も指定しない場合、idで指定されたコンテナの内容をすべてresponseTextで置き換えますが、positionを指定していると、特定の位置にreponseTextを挿入します。指定できる位置は以下の4通りです。
  • Before ... コンテナの直前。(コンテナの外側)
  • Top ... コンテナの一番上。(コンテナの内側)
  • Bottom ... コンテナの一番下。(コンテナの内側)
  • After ... コンテナの直後。(コンテナの外側)
type
synchronousかasynchronousを指定します。デフォルトはasynchronousです。
callback
xmlHttpRequestのreadyStateに応じて呼び出す関数を指定します。callbackには以下の種類があります。
  • loading ... readyStateが1の時に呼び出す関数を指定します。
  • loaded ... readyStateが2の時に呼び出す関数を指定します。
  • interactive ... readyStateが3の時に呼び出す関数を指定します。
  • complete ... readyStateが4の時に呼び出す関数を指定します。

実際にこのメソッドが吐き出すHTMLコードを見るために、

print $prototype->form_remote_tag({
    url => '/url',
    update => 'id',
    type => 'synchronous',
    loading => 'loading()',
});

というコードを実行してみると、以下の様に出力されます。

<form onsubmit=" new Ajax.Updater( 'id',  '/url', { parameters: Form.serialize(this),asynchronous: 0,onLoading: function(request){loading()} } ) ; return false;">

$prototype->link_to_function( $name, $function )

このメソッドでは、$functionを呼び出す、$nameで指定したアンカーを持つリンクを生成します。実行すれば一目瞭然、ってことで、

print $prototype->link_to_function( "Greeting", "alert('Hello World!')" );

と実行すると、

<a href="#" onClick="alert('Hello World!'); return false;">Greeting</a>

というHTMLを吐きますし、

print $prototype->link_to_function( '<img src="really.png"/>', 'do_delete()' );

と実行すると、

<a href="#" onClick="do_delete(); return false;"><img src="really.png"/></a>

というHTMLを吐きます。

$prototype->link_to_remote( $id, \%options )

このメソッドでは、指定したURLに対してxmlHttpRequestでリクエストする様なリンクを返します。オプションと説明は以下の通りです。

$prototype->link_to_remote( 
    'anchor', {
            with => 'name=value',
        url    => 'url',
        update => 'id',
        type => 'synchronous',
        callback => 'callback()',
    })
anchor
リンクのanchorを指定します。
with
GETのQUERY_STRINGまたはPOSTのbodyとして送信するデータを、name=valueといった形で指定します。
その他のオプション
$prototype->form_remote_tag(\%options)と同じです。

実際にこのメソッドが吐き出すHTMLコードを見るために、

print $prototype->link_to_remote( 
                  'anchor', 
                  {
                      update => 'id',
                      url    => 'url',
                      type => 'synchronous',
                  } );

というコードをを実行すると、

<a href="#" onClick=" new Ajax.Updater( 'id',  'url', { asynchronous: 0 } ) ; return false;">anchor</a>

というHTMLを吐きます。

$prototype->observe_field( $id, \%options)

このメソッドでは、$idで指定されたidを持つフィールドを監視して、変更があればxmlHttpRequestでリクエストを出すようなスクリプトを返します。%optionsは$prototype->form_remote_tag(\%options)と同じです。

実際にこのメソッドが吐き出すJavascriptコードを見るために、

print $prototype->observe_field( 
                  'field_id', 
                  {
                      update => 'id',
                      url    => 'url',
                      type => 'synchronous',
                  } );

と実行すると、

<script type="text/javascript">
<!--
new Form.Element.Observer( 'field_id', 2, function( element, value ) {  new Ajax.Updater( 'id',  'url', { parameters: value,asynchronous: 0 } )  } );
//-->
</script>

というJavascriptコードを吐きます。

$prototype->observe_form( $id, \%options )

$prototype->observe_fieldと基本的に同じですが、$idで指定されたフォーム全体を監視して、変更があればxmlHttpRequestでリクエストを出すようなスクリプトを返します。%optionsは$prototype->form_remote_tag(\%options)や他と同じです。

実際にこのメソッドが吐き出すJavscriptコードを見るために、

print $prototype->observe_form( 
            'form_id', 
            {
                update => 'id',
                url    => 'url',
            });

と実行すると、

<script type="text/javascript">
<!--
new Form.Observer( 'form_id', 2, function( element, value ) {  new Ajax.Updater( 'id',  'url', { parameters: value,asynchronous: 1 } )  } );
//-->
</script>

というJavascriptコードを吐きます。

$prototype->periodically_call_remote( \%options )

このメソッドでは、xmlHttpRequestによるサーバへのリクエストを、一定間隔で呼び出すようなスクリプトを返します。$options->{frequency}で時間を秒間隔で指定します。(デフォルト2秒。)他のオプションについては、他のメソッドと同様です。

print $prototype->periodically_call_remote({
                      update => 'id',
                      url    => 'url',
                  });

と実行すると、

<script type="text/javascript">
<!--
new PeriodicalExecuter( function () {  new Ajax.Updater( 'id',  'url', { asynchr
onous: 1 } )  }, 10 );
//-->
</script>

というJavascriptコードを吐きます。

$prototype->submit_to_remote( $name, $value, \%options )

このメソッドでは、$name, $valueで指定されたnameとvalueをxmlHttpRequestでsubmitするボタンを生成します。%optionsは他のメソッドと同様です。

実際にこのメソッドが吐き出すHTMLコードを見るために、

print $prototype->submit_to_remote(
                   'name',
                   'value',
                   {
                       update => 'id',
                       url    => 'url',
                   });

と実行すると、

<input type="button" name="name" value="value" onsubmit=" new Ajax.Updater( 'id',  'url', { asynchronous: 1 } ) ; return false;"/>

というHTMLコードを吐きます。

Catalystのビューから呼び出す方法

HTML::Prototypeのメソッドを、Catalystのビューから呼び出すためには、テンプレートに以下の様に記述します。

[% c.prototype.observe_field( 'editor', {
        url    => 'url',
        with   => "'body='+value",
        update => 'view'
    }) %]

ご覧頂くと分かるように、オプションの渡し方は、perlでのメソッド呼び出しと何ら変わりありませんので、詳細は省きます。(手抜きですんません。HTML::Prototypeの説明で力尽きました。)