TeedaをTABでAJAX

環境

標準的なTeedaS2Daoの環境をDoltengを利用して作成して利用しています。

起動

データベースにH2を利用していますので、プロジェクトを立ち上げてH2の起動と、Tomcatの起動をしておきます。

DB構造投入

サンプルで入っている /src/main/resources/data/demo.sql をH2に流しこんでサンプルデータを作成します。

概要

index.htmlがトップページとなり、tab1.htmlとtab2.htmlを読み込んだページです。通常と違うのはタブの中身をjQueryを利用してAjaxでロードしています。

index.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns:te="http://www.seasar.org/teeda/extension">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="css/default.css" />
<title>タブのテスト</title>

<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/jquery.metadata.js"></script>
<script type="text/javascript" src="js/jquery.tablesorter.js"></script>
<script type="text/javascript" src="js/ui.core.js"></script>
<script type="text/javascript" src="js/ui.tabs.js"></script>
<script type="text/javascript" src="js/jquery.timer.js"></script>

<link rel="stylesheet" href="css/style.css" type="text/css" media="all" />
<link rel="stylesheet" href="css/ui.tabs.css" type="text/css" media="all" />

<script type="text/javascript">
	var tab1Filter = "";
	var tab2Filter = "";

	$(function() {
		$("#a-tab-1").click( function(ev) {
			$("#tabbody-2").text( "tab2 loading..." );
			$("#tabbody-1").load( "tab1.html",{tab1Filter:tab1Filter},
				function() {
					$("#tabbody-1 > .tablesorter").tablesorter();
				});
		});
		$("#a-tab-2").click( function(ev) {
			$("#tabbody-1").text( "tab1 loading..." );
			$("#tabbody-2").load( "tab2.html",{tab2Filter:tab2Filter},
				function() {
					$("#tabbody-2 > .tablesorter").tablesorter();
				});
		});

		$('#maintabs > ul').tabs();

		$.timer(0, function (timer) {
			$("#a-tab-1").click();
			timer.stop();
		});

	});

	function tab1filter() {
		tab1Filter = $("#tab1Filter").val();
		$("#a-tab-1").click();
	};
	function tab2filter() {
		tab2Filter = $("#tab2Filter").val();
		$("#a-tab-2").click();
	};

</script>
</head>
<body>

<h1>Ajaxテスト</h1>

<div id="maintabs" style="width:100%;">
	<ul>
		<li><a href="#tab-1" id="a-tab-1"><span>DEPT</span></a></li>
		<li><a href="#tab-2" id="a-tab-2"><span>EMP</span></a></li>
	</ul>

	<div id="tab-1">
		<div id="tabbody-1">tab1 loading...
		</div>
	</div>

	<div id="tab-2">
		<div id="tabbody-2">tab2 loading...
		</div>
	</div>
</div>

</body>
</html>

基本的には単純なページであり、内部にはTeedaの処理もありません。今回はページクラスも作成していません。

jQueryの利用プラグイン

  1. tabs
  2. tablesorter
  3. timer

の3つです。上からタブ化、テーブルのソート、タイマー処理のスクリプトになります。流れ的にはタブ化した後に内容をloadで読み込んで、テーブルのソートを有効にしています。

初回のみ読み込まれていませんので、timerを使って読み込み処理を走らせています。

tab1.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns:te="http://www.seasar.org/teeda/extension">
<body>

<h1>DEPTの一覧</h1>

<form onsubmit="tab1filter();return false;">
	DEPT_NAMEの検索 <input id="tab1Filter" type="text" name="filter" />
	<input type="submit" value="フィルタ" />
</form>

<table class="tablesorter">
	<thead>
		<tr>
			<th>ID</th>
			<th>DEPT_NO</th>
			<th>DEPT_NAME</th>
			<th>LOC</th>
			<th>VERSION_NO</th>
		</tr>
	</thead>
	<tbody id="deptItems">
		<tr>
			<td><span id="id">ID</span></td>
			<td><span id="deptNo">DEPT_NO</span></td>
			<td><span id="deptName">DEPT_NAME</span></td>
			<td><span id="loc">LOC</span></td>
			<td><span id="versionNo">VERSION_NO</span></td>
		</tr>
	</tbody>
</table>

</body>
</html>

formがある以外は普通の処理になります。formではindex.htmlにあるtab1filter()を呼んだあとにreturn falseを返すことでページ遷移を防いでいます。

tab1filter()では検索文字列をパラメーターに渡してtab1.htmlのリロードを行っています。

tab1.java

package tabtest.web;

import tabtest.entity.Dept;

import tabtest.dao.DeptDao;

public class Tab1Page {

	public String sortable;
	public int deptIndex;
	public Dept[] deptItems;
	public Long id;
	public Integer deptNo;
	public String deptName;
	public String loc;
	public Integer versionNo;

	public String tab1Filter = "";

	public DeptDao deptDao;

	public String initialize() {
		return null;
	}

	public String prerender() {
		if( tab1Filter == null || tab1Filter.equals("") ){
			this.deptItems = this.deptDao.selectAll();
		} else {
			this.deptItems = this.deptDao.selectByDeptName( '%' + tab1Filter + '%' );
		}
		return null;
	}

}

処理的にはシンプルです。パラメーターがセットされている場合のみselectByDeptName()でフィルタリングされた結果を返しています。

DeptDat.java

package tabtest.dao;

import org.seasar.dao.annotation.tiger.Arguments;
import org.seasar.dao.annotation.tiger.Query;
import org.seasar.dao.annotation.tiger.S2Dao;
import org.seasar.dao.annotation.tiger.Sql;

import tabtest.entity.Dept;

@S2Dao(bean=Dept.class)
public interface DeptDao {

	@Query( "ORDER BY ID DESC" )
	public Dept[] selectAll();

	@Arguments("ID")
	public Dept selectById(Long id);

	@Sql("SELECT * FROM dept WHERE dept_name LIKE /*dept_name*/'%A%' ORDER BY ID DESC")
	public Dept[] selectByDeptName(String dept_name);

	public int insert(Dept dept);

	public int update(Dept dept);

	public int delete(Dept dept);

}

selectByDeptName()を追加して、selectAll()にもORDER BYを追加してみました。

検索結果

こんな感じでなにか文字を入れてEnterかフィルタボタンを押すとフィルタリングされた結果が返されます。

EMPタブ

ほぼ同じでテーブルをEMPに変更した処理を入れています。

テーブルソート

完全にjQueryの処理ですが、題名をクリックするとソートができます。2次ソートも可能で、この画像の場合にはDEPT_NOをクリックした後に、SHIFTを押しながらSALを選択しています。

総括

Teeda側でこの手のソートや一部更新を行おうとすると非常に複雑な処理になりやすいです。JavaScriptで利用できる機能はJavaScriptで処理をしたほうが他のフレームワークなどに流用できるので楽だと思います。

またTeeda側のAJAXの機能に関しては基本的にテンプレートではなく、自分でタグを入れたStringを返すタイプの処理になるので、ある一定以上のデータ量の場合には今回のように別ページにして分離した方が楽だと思います。

件数の上限などは入れていませんが、ソートを考えると数百件までのリミットとして、ページャーなどはつけずに条件を入れて絞り込んでくださいとエラーを出したほうが好ましいです。

またタブになっている必要はないので、通常のdivに流し込むこともできます。

サンプルプロジェクト

http://akira.info/labs/test/20080908TabTest.zip
作ったEclipseプロジェクトがそのまま入っています。(13.6M)

注意

あまりお行事のいいことをしていませんので、考えてから使いましょう!

生成されるhtmlもちょっと汚いのでチェッカーでオールクリアにってのは難しいかもしれません。ただチェッカーとか使うとJavaScliptで読み込んでいる部分がチェックされないので逆にスコアがいいかもしれません(笑)

TreeとかGridとかTeedaの暗黒面?に手を出すんだったら、この手のJavaScriptの方がいいのかな? そう思っているうちに気が付いたらダークサイドに落ちていたりするんだよね。。。