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

Posted by Gosuke Miyashita Sat, 10 Sep 2005 08:52:00 GMT

changelog

  • typoを修正。positionの説明で「4通り」を「44通り」と書いていたので。そんなにあるわけない。(2005/05/13)
  • $prototype->form_remote_tagのオプションpostitionの説明を追加。(2005/04/30)

概要

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の説明で力尽きました。)

Comments

Leave a response

  1. Avatar
    YellowTurtle about 1 year later:

    初めまして。参考にさせてもらってます。
    あの、もしかしてなんですが、form_remote_tagメソッドのoptionの

    method =< 'post',
    というところは、
    action => 'post',
    じゃないと、IEなりFirefoxなりに怒られるのではないでしょうか。

    手元のSchientificLinux5 + Firefox1.5な環境とWindows2000 + IE6な環境で試した限り、「POSTは定義されていないよ〜」と言う感じで怒られてしまいました。

    いろいろwebを調べた限り、「action=>'post',」のように記述しているサイトが有ったので、同様に上記の2環境で試したところ、エラーメッセージが発生しなくなりました。

  2. Avatar
    mizzy about 1 year later:

    いや、正しいはずですよ。Ajax.Updater に渡すオプションを指定するものですので。

    method => post で指定すると、

    <form action="/url" method="post" onsubmit=" new Ajax.Updater( 'id',  '/url', { parameters: Form.serialize(this),asynchronous: 0,insertion: Insertion.Before,method: post } ) ; return false">
    

    となり、method: post というオプションが渡りますが、action => post だと、

    <form action="/url" method="post" onsubmit=" new Ajax.Updater( 'id',  '/url', { parameters: Form.serialize(this),asynchronous: 0,insertion: Insertion.Before } ) ; return false">
    

    となり、どこにも反映されていません。そもそそも、form_remote_tag には action => post を渡しても意味がないようです。

  3. Avatar
    YellowTurtle about 1 year later:

      mizzy さん
    ご返答頂き、有り難うございます。

    そもそそも、form_remote_tag には action => post を渡しても意味がないようです。

    なるほど。そうなのですか。
    たしかに手元の環境においても、生成されるJavascriptのコードにはとくに反映されていませんでした。

    ちなみにその後、再度ソースコード(Javascriptの)を確認しましたが、特にエラーらしいエラーも見付からず仕BR舞いです。
    とりあえず現在は、当該箇所からmethodの指定を省略して、問題なく動作しております。
    それにしても、FirefoxのJavascriptコンソールで見た、あのエラー(post not defined.)が気になりますので、もう少し見直してみます・・・^^;

Comments