ajax 関数

□未翻訳

□翻訳中

□翻訳完了(Omi Chiba)

■レビュー(細田謙二)

ajax 関数

web2py_ajax.htmlで、web2pyはajaxという関数を定義しています。これは、jQuery関数の$.ajaxを基にしていますが、それと混同しないでください。後者は前者より強力で、その使用方法については参照32と参照75を見てください。その一方で、前者は多くの複雑なタスクをこなすのに十分な機能を持ち、簡単に使用できます。

In web2py_ajax.html, web2py defines a function called ajax which is based on, but should not be confused with, the jQuery function $.ajax. The latter is much more powerful than the former, and for its usage, we refer you to ref.32 and ref.75. However, the former function is sufficient for many complex tasks, and is easier to use.

ajax関数はJavaScriptの関数で次のような構文になります:

The ajax function is a JavaScript function that has the following syntax:

1.

ajax(url, [id1, id2, ...], target)

この関数は、url(最初の引数)を非同期的に呼び出し、リスト(二つ目の引数)に含まれるidと同じ値のidを持つフィールドの値を渡し、そしてターゲット(3つ目の引数)と同じ値のidを持つタグの内部HTMLに結果を保存します。

It asynchronously calls the url (first argument), passes the values of the fields with the id equal to one of the ids in the list (second argument), then stores the response in the innerHTML of the tag with the id equal to target (the third argument).

defaultコントローラーの例です:

Here is an example of a default controller:

1.

2.

3.

4.

5.

def one():

return dict()

def echo():

return request.vars.name

対応する"default/one.html"ビュー:

and the associated "default/one.html" view:

1.

2.

3.

4.

5.

{{extend 'layout.html'}}

<form>

<input name="name" onkeyup="ajax('echo', ['name'], 'target')" />

</form>

<div id="target"></div>

入力フィールドに何かタイプして、キーを離す(onkeyup)と同時に、ajax関数が呼ばれ、name="name"フィールドの値が"echo"アクションに渡されます。このアクションはそのテキストをビューに送り返します。ajax関数はその結果を受け取り"target"DIVにechoの結果を表示します。

When you type something in the INPUT field, as soon as you release a key (onkeyup), the ajaxfunction is called, and the value of the name="name" field is passed to the action "echo", which sends the text back to the view. The ajax function receives the response and displays the echo response in the "target" DIV.

Evalターゲット

Eval target

ajax関数の3つ目の引数には":eval"ストリングを指定できます。これは、サーバーから返された文字列がドキュメント内に埋め込まれずに、代わりに評価されることを意味します。

The third argument of the ajax function can be the string ":eval". This means that the string returned by server will not be embedded in the document but it will be evaluated instead.

defaultコントローラーの例:

Here is an example of a default controller:

1.

2.

3.

4.

5.

def one():

return dict()

def echo():

return "jQuery('#target').html(%s);" % repr(request.vars.name)

対応する"default/one.html"ビューの例:

and the associated "default/one.html" view:

1.

2.

3.

4.

5.

{{extend 'layout.html'}}

<form>

<input name="name" onkeyup="ajax('echo', ['name'], ':eval')" />

</form>

<div id="target"></div>

こうすることで複数のターゲットを更新できるより複雑な結果を返せるようになります。

This allows for more complex responses that can update multiple targets.

自動補完

Auto-completion

web2pyにはFormsの章で説明したように組み込みの自動補完ウィジェットがあります。ここでは簡単なものを最初から作成してみます。

Web2py contains a built-in autocomplete widget, described in the chapter about Forms. Here we will build a simpler one from scratch.

上記のajax関数のもう一つの応用は自動補完です。月の名前を入力する入力フィールドを作成し、訪問者が不完全な名前をタイプすると、Ajaxリクエスト経由で自動補完を実施するようにします。応答すると、入力フィールドの下に自動補完のドロップボックスが現れます。

Another application of the above ajax function is auto-completion. Here we wish to create an input field that expects a month name and, when the visitor types an incomplete name, performs auto-completion via an Ajax request. In response, an auto-completion drop-box appears below the input field.

次のdefaultコントローラで実現できます:

This can be achieved via the following default controller:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

15.

def month_input():

return dict()

def month_selector():

if not request.vars.month: return ''

months = ['January', 'February', 'March', 'April', 'May',

'June', 'July', 'August', 'September' ,'October',

'November', 'December']

month_start = request.vars.month.capitalize()

selected = [m for m in months if m.startswith(month_start)]

return DIV(*[DIV(k,

_onclick="jQuery('#month').val('%s')" % k,

_onmouseover="this.style.backgroundColor='yellow'",

_onmouseout="this.style.backgroundColor='white'"

) for k in selected])

対応する"default/month_input.html"ビュー:

and the corresponding "default/month_input.html" view:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

15.

16.

{{extend 'layout.html'}}

<style>

#suggestions { position: relative; }

.suggestions { background: white; border: solid 1px #55A6C8; }

.suggestions DIV { padding: 2px 4px 2px 4px; }

</style>

<form>

<input type="text" id="month" name="month" style="width: 250px" /><br />

<div style="position: absolute;" id="suggestions"

class="suggestions"></div>

</form>

<script>

jQuery("#month").keyup(function(){

ajax('month_selector', ['month'], 'suggestions')});

</script>

訪問者が"month"入力フィールドに何かタイプするたびにビューのjQueryスクリプトがAjaxリクエストを実行します。入力フィールドの値はAjaxリクエストによって"month_selector"アクションに送信されます。このアクションは送信された(選択された)テキストで始まる月の名前のリストを検索し、DIVのリスト(それぞれが候補の月の名前を含む)を作成し、シリアライズされたDIVの文字列を返します。ビューは返されたHTMLを"suggestions"DIVに表示します。"month_selector"アクションは候補とDIVに埋め込まれたJavaScriptコードの両方を作成します。JavaScriptコードは訪問者がそれぞれの候補をクリックするたびに実行されます。例えば、訪問者が"Ma"とタイプすると、コールバックアクションは次の結果を返します:

The jQuery script in the view triggers the Ajax request each time the visitor types something in the "month" input field. The value of the input field is submitted with the Ajax request to the "month_selector" action. This action finds a list of month names that start with the submitted text (selected), builds a list of DIVs (each one containing a suggested month name), and returns a string with the serialized DIVs. The view displays the response HTML in the "suggestions" DIV. The "month_selector" action generates both the suggestions and the JavaScript code embedded in the DIVs that must be executed when the visitor clicks on each suggestion. For example when the visitor types "Ma" the callback action returns:

1.

2.

3.

<div onclick="jQuery('#month').val('February')"

onmouseout="this.style.backgroundColor='white'"

onmouseover="this.style.backgroundColor='yellow'">February</div>

最終的なエフェクトは:

Here is the final effect:

もし月の名前が次のようにデータベーステーブルに保存されている場合は:

If the months are stored in a database table such as:

1.

db.define_table('month', Field('name'))

シンプルにmonth_selectorアクションを次のように置き換えるだけです:

then simply replace the month_selector action with:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

def month_input():

return dict()

def month_selector():

it not request.vars.month:

return "

pattern = request.vars.month.capitalize() + '%'

selected = [row.name for row in db(db.month.name.like(pattern)).select()]

return ".join([DIV(k,

_onclick="jQuery('#month').val('%s')" % k,

_onmouseover="this.style.backgroundColor='yellow'",

_onmouseout="this.style.backgroundColor='white'"

).xml() for k in selected])

jQueryは追加機能を持つオプション的な自動補完プラグインをもちますが、ここでは説明しません。

jQuery provides an optional Auto-complete Plugin with additional functionalities, but that is not discussed here.

Ajaxフォーム送信

Ajax Form Submission

asynchronous

ページ全体をリロードしないでAjaxを利用してメッセージを送信することができるページを考えてみましょう。13章で後述しますが、LOADヘルパーを利用することで、web2pyはここで説明する内容よりもより良い仕組みを提供しています。ここではjQueryを使ったシンプルなやり方をお見せします。

Here we consider a page that allows the visitor to submit messages using Ajax without reloading the entire page. Using the LOAD helper, web2py provides a better mechanism for doing it than described here, which will be described in Chapter 13. Here we want to show you how to do it simply using jQuery.

"myform"フォームと"target"DIVがあります。フォームが送信されると、サーバーはそれを許可(そしてデータベースへの挿入を実行する)するか、拒否(バリデーションをパスしなかったので)します。対応するメッセージがAjaxレスポンスで返されて"target"DIVに表示されます。

It contains a form "myform" and a "target" DIV. When the form is submitted, the server may accept it (and perform a database insert) or reject it (because it did not pass validation). The corresponding notification is returned with the Ajax response and displayed in the "target" DIV.

次のモデルを持つtestアプリケーションを作成してください:

Build a test application with the following model:

1.

2.

3.

db = DAL('sqlite://db.db')

db.define_table('post', Field('your_message', 'text'))

db.post.your_message.requires = IS_NOT_EMPTY()

それぞれの投稿は"your_message"という入力必須の単一フィールドを持つ点に注意してください。

Notice that each post has a single field "your_message" that is required to be not-empty.

default.pyコントローラを編集して次の二つのアクションを書いてください:

Edit the default.py controller and write two actions:

1.

2.

3.

4.

5.

6.

7.

8.

9.

def index():

return dict()

def new_post():

form = SQLFORM(db.post)

if form.accepts(request.vars, formname=None):

return DIV("Message posted")

elif form.errors:

return TABLE(*[TR(k, v) for k, v in form.errors.items()])

最初のアクションは単にviewを返すだけです。

The first action does nothing other than return a view.

二つ目のアクションはAjaxのコールバックです。これは、request.vars内のフォーム変数を待ち、それらを処理して、成功時にはDIV("Message posted")を返し、失敗時にはエラーメッセージのTABLEを返すものです。

The second action is the Ajax callback. It expects the form variables in request.vars, processes them and returns DIV("Message posted") upon success or a TABLE of error messages upon failure.

"default/index.html"ビューを次のように編集してください:

Now edit the "default/index.html" view:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

15.

16.

{{extend 'layout.html'}}

<div id="target"></div>

<form id="myform">

<input name="your_message" id="your_message" />

<input type="submit" />

</form>

<script>

jQuery('#myform').submit(function() {

ajax('{{=URL('new_post')}}',

['your_message'], 'target');

return false;

});

</script>

この例はHTMLを利用して手動でフォームが作成されていますが、フォームを表示しているのとは異なるアクションのSQLFORMで処理されている点に注意してください。SQLFORMオブジェクトはHTMLにシリアライズされることはありません。この場合はSQLFORM.acceptsはセッションを受け取らずformname=Noneをセットします、これは手動のHTMLフォームにおいてフォーム名とフォームキーをセットしないようにしたからです。

Notice how in this example the form is created manually using HTML, but it is processed by the SQLFORM in a different action than the one that displays the form. The SQLFORM object is never serialized in HTML. SQLFORM.accepts in this case does not take a session and setsformname=None, because we chose not to set the form name and a form key in the manual HTML form.

ビューの下部にあるスクリプトは"myform"送信ボタンとインラインの関数を関連付けています。インラインの関数は、web2pyのajax関数を利用してid="your_message"を持つ入力フィールドを送信し、id="target"を持つDIVの中にその答えを表示します。

The script at the bottom of the view connects the "myform" submit button to an inline function which submits the INPUT with id="your_message" using the web2py ajax function, and displays the answer inside the DIV with id="target".

投票と評価

Voting and Rating

もう一つのAjaxアプリケーションはページにおいてアイテムへ投票または評価するものです。投稿された画像に投票できるアプリケーションを考えてみます。そのアプリケーションは投票結果に応じてソートされた画像を表示する単一のページからなります。ここでは、訪問者が複数回投票できるようになっています。ただし、訪問者が認証されていればこの動きを変えるのは簡単です。データベースの個人の投票数をトラックして投票者のrequest.env.remote_addrに関連付ければいいのです。

Another Ajax application is voting or rating items in a page. Here we consider an application that allows visitors to vote on posted images. The application consists of a single page that displays the images sorted according to their vote. We will allow visitors to vote multiple times, although it is easy to change this behavior if visitors are authenticated, by keeping track of the individual votes in the database and associating them with the request.env.remote_addr of the voter.

シンプルなモデルを示します:

Here is a sample model:

1.

2.

3.

4.

db = DAL('sqlite://images.db')

db.define_table('item',

Field('image', 'upload'),

Field('votes', 'integer', default=0))

defaultコントローラ:

Here is the default controller:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

def list_items():

items = db().select(db.item.ALL, orderby=db.item.votes)

return dict(items=items)

def download():

return response.download(request, db)

def vote():

item = db.item[request.vars.id]

new_votes = item.votes + 1

item.update_record(votes=new_votes)

return str(new_votes)

downloadアクションは、list_itemsビューが"uploads"フォルダに保存されている画像をダウンロードできるようにするために必要です。voteアクションはAjaxのコールバックで使用されます。

The download action is necessary to allow the list_items view to download images stored in the "uploads" folder. The votes action is used for the Ajax callback.

"default/list_items.html"ビュー:

Here is the "default/list_items.html" view:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

{{extend 'layout.html'}}

<form><input type="hidden" id="id" name="id" value="" /></form>

{{for item in items:}}

<p>

<img src="{{=URL('download', args=item.image)}}"

width="200px" />

<br />

Votes=<span id="item{{=item.id}}">{{=item.votes}}</span>

[<span onclick="jQuery('#id').val('{{=item.id}}');

ajax('vote', ['id'], 'item{{=item.id}}');">vote up</span>]

</p>

{{pass}}

訪問者が"[vote up"]をクリックすると、JavaScriptコードはitem.idの値を隠し"id"入力フィールドに保存し、Ajaxリクエストでサーバーに値を送信します。サーバーは対応するレコードの投票数を増やし、新しい投票数を文字列で返します。そしてこの値がターゲットのitem{{=item.id}} SPANに挿入されます。

When the visitor clicks on "[vote up]" the JavaScript code stores the item.id in the hidden "id" INPUT field and submits this value to the server via an Ajax request. The server increases the votes counter for the corresponding record and returns the new vote count as a string. This value is then inserted in the target item{{=item.id}} SPAN.

Ajaxのコールバックはバックグラウンドで計算を実行するのに利用できますが、cronか(4章で説明した)バックグラウンド処理を使用するのを推奨します。webサーバーはスレッドを強制的にタイムアウトするからです。もし計算に時間がかかり過ぎると、webサーバーは処理を中断します。タイムアウト値のセット方法はあなたのwebサーバーのパラメータを参照してください。

Ajax callbacks can be used to perform computations in the background, but we recommend using cron or a background process instead (discussed in chapter 4), since the web server enforces a timeout on threads. If the computation takes too long, the web server kills it. Refer to your web server parameters to set the timeout value.