DataTable Control: Custom Cell Formatting

このExampleの目的は、

  1. カスタムのフォーマッターを作ってみること(タイトルの通り)。
  2. デフォルトのフォーマッターをoverrideしてみること(Javascriptの場合は、overrideというよりも、むしろ置換してしまう、という言い方の方が正しい)。
  3. 色々な入力項目(radioボタン、checkボックス、listボックス、ボタン)が押されたときの挙動と確認すること。

である。
1,2番目の項目については、その引数と使い方。
3番目については、入力項目の変更イベントをListenして、何か渡ってきて、それからどのように情報を引き出すか、ということが実践では必要になってくる。

また、この例に、(図らずも)YUI Loaderを初めて使うこととなった。

以下が、サンプリングした画面画面である。
外見上は、YUIのExampleから、日付のフォーマット(MM/DD/YYYYをYYYY/MM/DDに変更)と、通貨コード("$" Dollar Markを"¥" YEN Markに変更)を変更してある。

入力イベント(チェックボックスのチェックなど)が発生した際、イベントハンドラに渡ってくるもの(引数)のうち主要な役割を果たすのは、引数.targetで取得できるHTMLInputElementであって、これを起点として、変更レコードの取得などが可能となる。
また、レコードはRecordオブジェクトとして取得することができ、getData()メソッドによりDataSourceのfields属性として定義したcolumn要素が取得できる。また、setaData()メソッドにより、Recordオブジェクトの変更が可能である。
DataTableは、原則として、tableタグから生成されている場合と同じであるから、Styleの変更などは、先の例「DataTable Control: Progressive Enhancement」に習えばよい。
1コラム目は、bg-colorを、field3が100より大きければ青、以外であれば赤として、画像の入れ替えを行うというカスタムフォーマッターにより編集される。これも、tdの子要素であるテキストノード(これが、フォーマッターに渡ってくるElementとなる)と、tdタグ(Elementのparentとなる)のclass属性のコントロールで行うことができる。

以下に、Javascriptを含む、HTMLの全文をしめす。
ソースコード中、イベントハンドラーはある程度統一感を持たせるように変更を加えてある。
また、各入力要素に関して(イベントハンドラに渡ってくる引数が同じことを確認するため)のAlertが上がるようにしている。
最後にYUI Loaderであるが、これを用いた場合の「適切なコードスタイル」が思いつかなかったため、コードの形式はYUIのExampleの形式をそのまま採用した。
YUI Loaderは、機能をrequireすることで、必要なモジュール、CSS(の依存性を解決して)読み込んでくる「優れもの」であるが、実際の開発局面では、あまり使わないのではないかと思われる(YUIモジュールをそのまま無条件に使うという前提に縛られてしまうため)。

<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<TITLE>Ajax_Sampling</TITLE>

<style type="text/css">
body {
	margin:0;
	padding:0;
}
</style>

<style type="text/css" id="defaultstyle">
#main {
	margin: 2px;
	padding: 3px;
/*
	width: 560px;
	height: auto;
	border:1px dashed #999999;
*/
}

/* ※1 */
.yui-skin-sam .yui-dt tbody td.up {
	background-color: #efe;
}
.yui-skin-sam .yui-dt tbody td.down {
    background-color: #fee;
}

/* 実験 1: thead th の範囲*/
.yui-skin-sam .yui-dt thead th {
	font-weight: bold;
}

/* 実験 2: tbody tds の範囲*/
.yui-skin-sam .yui-dt tbody td {
	color: purple;
}

</style>

<script type="text/javascript" src="scripts/yui/yuiloader/yuiloader.js"></script> 

<!--  データテーブルの読み込み  -->
<!-- field2では、new Date(2007, 1, 1)と指定
YAHOO.example.Data = {
    multitypes: {
        items: [
            {field1: "bananas", field2:new Date(2007, 1, 1), field3:111, field4:"23.4", field5:"bob", field6:"http://www.yahoo.com"},
            {field1: "cherries", field2:new Date(2006, 1, 1), field3:12.3, field4:"35.12", field5:"ann", field6:"http://www.yahoo.com"},
            {field1: "apples", field2:new Date(2007, 11, 1), field3:1, field4:34.12, field5:"charlie", field6:"http://www.yahoo.com"},
            {field1: "bananas", field2:new Date(2007, 1, 11), field3:1112, field4:"03", field5:"diane", field6:"http://www.yahoo.com"},
            {field1: "cherries", field2:new Date(1999, 1, 11), field3:124, field4:03, field5:"edgar", field6:"http://www.yahoo.com"},
            {field1: "bananas", field2:"January 10, 2005", field3:"12", field4:"34", field5:"francine", field6:"http://www.yahoo.com"},
            {field1: "apples", field2:"January 1, 2005", field3:"19.1", field4:"234.5", field5:"george", field6:"http://www.yahoo.com"},
            {field1: "bananas", field2:"1/11/05", field3:"10.02", field4:"345.654", field5:"hannah", field6:"http://www.yahoo.com"},
            {field1: "cherries", field2:"1/11/2005", field3:"109", field4:23.456, field5:"igor", field6:"http://www.yahoo.com"},
            {field1: "bananas", field2:"November 1, 2005", field3:"11111", field4:23.0123, field5:"julie", field6:"http://www.yahoo.com"}
        ]
    },
}
-->
<!-- データテーブル -->
<script type="text/javascript" src="scripts/yui/datatable/assets/js/data.js"></script> 

<script type="text/javascript">
var loader = new YAHOO.util.YUILoader();
loader.insert({
	// loaderで読み込みたいmoduleをしてい。fonts(css)、datatable(js)、json(js)を指定している。
    require: ["fonts", "datatable", "json"],
	// debugレベルのモジュールも使用する。
    filter: 'debug',
	// 読み込み元をローカルの特定ディレクトリに指定
    base: 'scripts/yui/',
    // loadに成功したとき
    onSuccess: function() {
        YAHOO.example.CustomFormatting = function() {
            // Define a custom formatter for the Column labeled "flag"
            // draws an up icon and adds class "up" to the cell liner to affect
            // a green background color if value of field3 is greater than 100.
            // Otherwise renders a down icon and assigns class "down", setting
            // the background color to red.
            
            // カスタム・フォーマッターの作り方(引数)
            var myCustomFormatter = function(elCell, oRecord, oColumn, oData) {
                if(oRecord.getData("field3") > 100) {
                    // elCell(Textノード)の親ノード(td)のclassをupにすることで、色を変える。
                    // 上※1参照; .yui-dt tbody td.up 
                    YAHOO.util.Dom.replaceClass(elCell.parentNode, "down", "up");
                    elCell.innerHTML = 
                        	'&nbsp;<img src="scripts/yui/datatable/assets/skins/sam/dt-arrow-up.png">';
                }
                else {
                    YAHOO.util.Dom.replaceClass(elCell.parentNode, "up","down");
                    elCell.innerHTML = 
                        	'&nbsp;<img src="scripts/yui/datatable/assets/skins/sam/dt-arrow-dn.png">';
                }
            };
            
            // Add the custom formatter to the shortcuts
            // 「YAHOO.widget.DataTable.Formatter.」までが、YAHOOで規定されている、フォーマッターの名前空間
            // これにmtCustomを追加する。
            YAHOO.widget.DataTable.Formatter.myCustom = myCustomFormatter;
 
            // Override the built-in formatter
            // フォーマッターの上書き(引数)
            YAHOO.widget.DataTable.formatEmail = function(elCell, oRecord, oColumn, oData) {
                var user = oData;
                elCell.innerHTML = "<a href=\"mailto:" + user + "@mycompany.com\">" + user + "</a>";
            };
 
            var myColumnDefs = [
                {key:"flag", formatter:"myCustom"}, // use custom shortcut
                {key:"radio", formatter:"radio"}, // use the built-in radio formatter
                {key:"check", formatter:"checkbox"}, // use the built-in checkbox formatter (shortcut)
                {key:"button", label:"Show record data", formatter:YAHOO.widget.DataTable.formatButton}, // use the built-in button formatter
                {key:"field1", formatter:"dropdown", dropdownOptions:["apples","bananas","cherries"],sortable:true},
                {key:"field2", sortable:true, formatter:"date"}, // use the built-in date formatter
                {key:"field3", sortable:true, formatter:"number"},
                {key:"field4", sortable:true, formatter:"currency"}, // use the built-in currency formatter
                {key:"field5", sortable:true, formatter:YAHOO.widget.DataTable.formatEmail}, // use the overridden email formatter
                {key:"field6", sortable:true, formatter:YAHOO.widget.DataTable.formatLink} // use the built-in link formatter
            ];

            // データの読み込み※2
            var myDataSource = new YAHOO.util.DataSource(YAHOO.example.Data.multitypes);
            // 読み込んだデータをparseする時のタイプを指定
            myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
            // 読み込んだデータをparseする時のタイプを指定
            // YUIのDataSourceのページ(http://developer.yahoo.com/yui/datasource/)のJSONの項を参照。
            myDataSource.responseSchema = {
                // JSONデータのどのノードを使うか? ※2では、YAHOO.example.Dataのmultitypesまでを指定。
                resultsList: "items",
                // 読み込むデータとパーサーを指定して、RecordSetを生成させる。
                fields: [
                    {key:"field1", parser:"string"}, // point to the string parser
                    {key:"field2", parser:"date"}, // point to the date parser
                    {key:"field3", parser:"number"}, // point to the number parser
                    {key:"field4", parser:"number"}, // point to the number parser
                    {key:"field5"}, // this is already string data so no parser needed
                    {key:"field6"} // this is already string data so no parser needed
                ]
            };
 
            var myDataTable 
            	= new YAHOO.widget.DataTable("formatting", 
                    						myColumnDefs, 
                    						myDataSource,
                        					// APIドキュメント http://developer.yahoo.com/yui/docs/YAHOO.widget.DataTable.html
                        					// のConfiguration Attributesを参照のこと。 
                        					{caption:"キャプション",
        									// Yen markを出すにはhtml表現。
                                             currencyOptions:{prefix: "&#x00a5;", decimalPlaces:2, decimalSeparator:".", thousandsSeparator:","},
         									// 年月日に変更
                                             dateOptions:{format:"%Y/%m/%d", locale:"ja"}
                            			});

            //-------- 以下、イベントハンドラー  ---------------------
            
            // radioボタンクリック時のイベントハンドラ
            var lastSelectedRadioRecord = null;
            myDataTable.subscribe("radioClickEvent", function(oArgs){
                if(lastSelectedRadioRecord) {
                    lastSelectedRadioRecord.setData("radio",false);
                }
				// oArgs.targetの戻りはHTMLInputElement。
                var elRadio = oArgs.target;
                // チェックされたレコードオブジェクトの取得
                var oRecord = this.getRecord(oArgs.target);
                // oRecord.getData()でDataSourceで定義したresponseSchema.fieldsの中身が取れる。
                alert('oRecord: '+YAHOO.lang.dump(oRecord,1));
                // oRecordの操作はDataTableインスタンスのcolumn定義に従って行うことが出来る。
                // (注) radioはデータではない。
                oRecord.setData("radio",true);
				// 選ばれたRecordオブジェクトの保管
                lastSelectedRadioRecord = oRecord;
                var name = oRecord.getData("field5");
            });
 
            // checkboxクリック時のイベントハンドラ
            myDataTable.subscribe("checkboxClickEvent", function(oArgs){
                var elCheckbox = oArgs.target;
                // チェックされたレコードオブジェクトの取得
                var oRecord = this.getRecord(oArgs.target);
				// oArgs.target=HTMLInputElement
                alert('oArgs.target: '+YAHOO.lang.dump(oArgs.target));
                oRecord.setData("check",elCheckbox.checked);
            });
 
            // buttonクリック時のイベントハンドラ
            myDataTable.subscribe("buttonClickEvent", function(oArgs){
                // チェックされたレコードオブジェクトの取得
                var oRecord = this.getRecord(oArgs.target);
                alert('oRecord.getData(): '+YAHOO.lang.dump(oRecord.getData()));
            });
 
            // リストボックス変更時のイベントハンドラ
            myDataTable.subscribe("dropdownChangeEvent", function(oArgs){
                var elDropdown = oArgs.target;
                // チェックされたレコードオブジェクトの取得
                var oRecord = this.getRecord(oArgs.target);
                alert('変更前 oRecord.getData(): '+YAHOO.lang.dump(oRecord.getData()));
                oRecord.setData("field1",elDropdown.options[elDropdown.selectedIndex].value);
                alert('変更後 oRecord.getData(): '+YAHOO.lang.dump(oRecord.getData()));
            });
            
            return {
                oDS: myDataSource,
                oDT: myDataTable
            };
        }();
    }
});
</script>
</HEAD>

<BODY class="yui-skin-sam">
<div id="main">
<p>
DataTableの動きをチェックするサンプルです。
</p>
<div id="formatting"></div>
</div>
</BODY>
</HTML>