ブログが続かないわけ

この日記のはてなブックマーク数
Webエンジニアが思うこと by junichiro on Facebook

入力チェックエラー後に、エラー画面ではなく入力画面を再表示する場合のSmartyテンプレートの書き方例

このエントリーを含むはてなブックマーク hateb
入力画面で入力した内容に誤りがあった場合、画面遷移としては下記の2パターンが考えられる。

A. エラー画面を表示して、エラー内容を提示し、戻るボタンで入力画面に戻ってもらう。
入力画面→エラー画面→入力画面→確認画面→完了画面

B. エラー内容を入力画面に提示する。
入力画面→入力画面(エラー表示)→確認画面→完了画面

B. のパターンの方がユーザーにとって2つの利点がある。
■1. 画面遷移がAに比べて1ステップ少なく済む。(何度も間違える場合は、より効果的)
■2. 入力画面にエラーが表示されているので、自分のエラーを確認しながら入力できる。

しかし、B.のパターンを実装するとなると、ユーザーの入力内容をどう保持するかというところが若干難しくなる。A.のパターンではPCならブラウザの戻るボタンもしくはhistory.back()を使えばよいので、ユーザーの入力した内容というのは、プログラマが特に意識しなくても保持されている。しかし、B.のパターンはおそらく確認画面ロジック内で、入力内容にエラーがあった場合にテンプレートだけを確認画面の物ではなく入力画面のものに差し替えるという方法をとるのだと思う。そのとき、何も意識しなければ入力内容はなんら保持されず、ユーザーはいちからやり直しとなってしまう。

みなさん入力内容の保持をいろいろな方法で実装されていると思うが、「これ」という決め手のような実装方法があまり見当たらなかったので、自分のやり方を晒してみる。まずPHP側。
public function init() {
$this->q = $this->_getAllParams();
$this->view->assign( 'q', $this->q );
}
僕の場合はよくZendFrameworkを使うので、requestデータは「$this->_getAllParams()」で取得できる(ここはどんな方法でも構わない)。で、それを丸ごと配列のままテンプレートにアサインしてしまう。これを常に呼ばれるところ(僕の場合はinit()というメソッド)に書いておく。PHP側はこれだけ。

次にテンプレート側
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<title>入力</title>
</head>
<body>
{foreach item=errmsg from=$errmsgs}
{$errmsg}</br>
{/foreach}
<form action="confirm" method="get">
<input type="text" name="name" value="{$q.name|escape:'html'}"/>
<input type="radio" name="sex" value="男性"{if $q.sex eq '男性'} checked="checked"{/if} />男性
<input type="radio" name="sex" value="女性"{if $q.sex eq '女性'} checked="checked"{/if} />女性
<input type="checkbox" name="hobbies[]" value="サッカー"{if is_array($q.hobbies) && 'サッカー'|in_array:$q.hobbies} checked="checked"{/if} />サッカー
<input type="checkbox" name="hobbies[]" value="フットサル"{if is_array($q.hobbies) && 'フットサル'|in_array:$q.hobbies} checked="checked"{/if} />フットサル
<select name="area">
<option value="東"{if $q.area eq '東'} selected="selected"{/if} />東</option>
<option value="西"{if $q.area eq '西'} selected="selected"{/if} />西</option>
<option value="南"{if $q.area eq '南'} selected="selected"{/if} />南</option>
<option value="北"{if $q.area eq '北'} selected="selected"{/if} />北</option>
</select>
<textarea name="long_text">{$q.long_text|escape:'html'}</textarea>
<input type="submit" />
</form>
</body>
</html>
複数選択が可能なアイテムの部分で、is_arrayやin_arrayを使うのがコツ。

テンプレートにロジックが入るのを好まない人もたくさんいる(僕も以前はそうだった)ので、万人に受け入れられる方法ではないけれど、僕の中ではこれが一番おすすめ。

My Best Practice!

ちなみにPerlならFillInFormとかを使ってもっと簡単にできるよ!
この記事のトラックバックURL
http://en.yummy.stripper.jp/trackback/841275
トラックバック
コメント
チェックボックス、ラジオボタンの内容は配列に入れてassign、ループさせることが多いです。
内容をyamlで別ファイルにしておいたり、それが面倒だったら配列をベタで別ファイルに書いてインクルードしたりとか。
| makoto | 2008/03/13 7:28 PM |
そうですね。項目の内容はmakotoさんからご指摘いただいたように、なんらかの方法でPHP側で出力した方が簡単な場合が多いですね。

そもそも項目のリストなんかをDBでマスタ管理されていることも多いですし。

ただ、作業の分離の関係上、どうしてもデザイナ側が項目をいじらなければならないということがままあるんです。そういうときにこういう方法をとります。
| junichiro | 2008/03/13 10:00 PM |
わかってるよ、って話でしたね。失礼しました。
確かにデザイナさんが触らないといけない場合はその方がよいですね。
昔、こういうソースを見て、非常に萎えたのを思い出しました。
{if $q.sex eq '男性'}
<input type="radio" name="sex" value="男性" checked="checked" />男性
<input type="radio" name="sex" value="女性" />女性
else
<input type="radio" name="sex" value="男性" />男性
<input type="radio" name="sex" value="女性" checked="checked" />女性
{/if}
| makoto | 2008/03/14 10:06 PM |
これは萎えるわー。

しかも、これだとデザイナ側もラジオボタンが2重で表示されるから作業もしづらいし。

意外とロジックとデザインの分離って細かいところでは難しいですよね。
| junichiro | 2008/03/15 2:57 PM |









関連情報