Full Ajax な CRUD アプリケーション その5

今回は既存データの編集、削除機能を実装します。

編集・削除ウィンドウの作成

編集・削除ウィンドウは新規追加ウィンドウを再利用します。機能は一覧から一つのレコードを選択し値をフォームに読み込むようにします。

まずは選択できる行を一つだけにします。以下のようにExt.grid.RowSelectionModelを定義します。

	var selModel = new Ext.grid.RowSelectionModel({
		singleSelect:true
	});

	~

	var grid = new Ext.grid.GridPanel({
		title:'社員管理',
		stripeRows: true,
		autoExpandColumn: 'name',
		height:523,
		width:600,
		store: store,
		colModel: colModel,
		selModel: selModel,
		tbar: tbar,
		bbar: bbar
	});

	~

続いて編集・削除のハンドラーを定義します。gridで選択した行の値を取得しフォームへ代入します。変更不可の項目はreadOnly属性をtrueにします。

編集のハンドラー
	var editActionHandler = function(){
		var list = grid.selModel.getSelections();
		if (list.length > 0) {
			formWindow.show('編集', './update');
			var e = list[0];
			Ext.getDom('id').value = e.get('id');
			Ext.getDom('name').value = e.get('name');
			Ext.getDom('jobType').value = e.get('jobType');
			Ext.getDom('salary').value = e.get('salary');
			Ext.getDom('department').value = e.get('department');
			Ext.getDom('id').readOnly = true;
		}
	}
削除のハンドラー
	var deleteActionHandler = function(){
		var list = grid.selModel.getSelections();
		if (list.length > 0) {
			formWindow.show('削除', './delete');
			var e = list[0];
			Ext.getDom('id').value = e.get('id');
			Ext.getDom('name').value = e.get('name');
			Ext.getDom('jobType').value = e.get('jobType');
			Ext.getDom('salary').value = e.get('salary');
			Ext.getDom('department').value = e.get('department');
			Ext.getDom('id').readOnly = true;
			Ext.getDom('name').readOnly = true;
			Ext.getDom('jobType').readOnly = true;
			Ext.getDom('salary').readOnly = true;
			Ext.getDom('department').readOnly = true;
		}
	}

各ハンドラーをツールバーのボタンに割り当てます。

	var editAction = new Ext.Action({
		text: '編集',
		iconCls: 'editIcon',
		handler: editActionHandler
	});

	var deleteAction = new Ext.Action({
		text: '削除',
		iconCls: 'deleteIcon',
		handler: deleteActionHandler
	});
employee.js - 編集・削除機能の追加
Ext.onReady(function(){

	// HANDLER

	var addActionHandler = function(){
		formWindow.show('新規追加', './create');
		Ext.getDom('id').readOnly = true;
	}

	var editActionHandler = function(){
		var list = grid.selModel.getSelections();
		if (list.length > 0) {
			formWindow.show('編集', './update');
			var e = list[0];
			Ext.getDom('id').value = e.get('id');
			Ext.getDom('name').value = e.get('name');
			Ext.getDom('jobType').value = e.get('jobType');
			Ext.getDom('salary').value = e.get('salary');
			Ext.getDom('department').value = e.get('department');
			Ext.getDom('id').readOnly = true;
		}
	}

	var deleteActionHandler = function(){
		var list = grid.selModel.getSelections();
		if (list.length > 0) {
			formWindow.show('削除', './delete');
			var e = list[0];
			Ext.getDom('id').value = e.get('id');
			Ext.getDom('name').value = e.get('name');
			Ext.getDom('jobType').value = e.get('jobType');
			Ext.getDom('salary').value = e.get('salary');
			Ext.getDom('department').value = e.get('department');
			Ext.getDom('id').readOnly = true;
			Ext.getDom('name').readOnly = true;
			Ext.getDom('jobType').readOnly = true;
			Ext.getDom('salary').readOnly = true;
			Ext.getDom('department').readOnly = true;
		}
	}

	// MODEL, CONTROL

	var fields = [ 'id', 'name', 'jobType', 'salary', 'department' ];

	var store = new Ext.data.Store({
		proxy: new Ext.data.HttpProxy({
			url: './employee.json',
			method: 'GET'
		}),
		reader: new Ext.data.JsonReader({
		    root: 'root',
		    totalProperty: 'totalProperty',
			fields: fields
		})
	});

	// VIEW

	Ext.QuickTips.init();

	Ext.form.Field.prototype.msgTarget = 'side';

	var FormWindow = function(){
		var extWin = null;
		this.show = function(title, url){
			if (extWin == null) {
				var form = new Ext.FormPanel({
			    	method: 'POST',
					id: 'employee-form',
					baseCls: 'x-plain',
					labelWidth: 40, 
					defaults: {width: 190},
					defaultType: 'textfield',
					bodyStyle:'padding:5px 10px 0',
					items: [{
						fieldLabel: 'Id',
						id: 'id',
		    			xtype: 'numberfield'
					},{
						fieldLabel: '氏名',
						id: 'name',
						allowBlank: false
					},{
						fieldLabel: '職種',
						id: 'jobType'
					}, {
						fieldLabel: '給料',
						id: 'salary',
		    			xtype: 'numberfield'
					}, {
						fieldLabel: '部署',
						id: 'department'
					}]
				});
				extWin = new Ext.Window({
					title: '会社員情報 : ' + title,
					width: 300,
					height:220,
					minWidth: 300,
					minHeight: 250,
					layout: 'fit',
					closeAction :'hide',
					plain:true,
					bodyStyle:'padding:5px;',
					buttonAlign:'center',
					items: form,
					buttons: [{
						text: 'OK',
						handler: function(){
							form.getForm().submit({
								url: url,
								waitMsg: 'サブミットしています...', // Submit時に表示するメッセージ。二重サブミット防止にもなる。
								success: function(form, action) {
									Ext.select('.x-tbar-loading').item(0).dom.click();
									extWin.close();
									extWin = null;
								},
								failure: function(form, action) {
				   					if (action.failureType == 'client') {
				   						// do nothing
				   					} else if (action.failureType == 'connect') {
										Ext.MessageBox.alert('コネクションエラー', '通信時にエラーが発生しました。');
									} else {
										Ext.MessageBox.alert('失敗', title + 'できませんでした。');
										Ext.select('.x-tbar-loading').item(0).dom.click();
										extWin.close();
										extWin = null;
									}
								}
							});
						}
					},{
						text: 'キャンセル',
						handler: function(){
							form.getForm().reset();
							extWin.close();
							extWin = null;
						}
					}]
				});
			}
			extWin.show();
		}
	};
	var formWindow = new FormWindow();

	var colModel = new Ext.grid.ColumnModel([
		{header: "Id", width: 75, sortable: true, dataIndex: 'id'},
		{id:'name', header: "氏名", width: 160, sortable: true, dataIndex: 'name'},
		{header: "職種", width: 75, sortable: true, dataIndex: 'jobType'},
		{header: "給与", width: 75, sortable: true, dataIndex: 'salary'},
		{header: "部署", width: 85, sortable: true, dataIndex: 'department'}
	]);

	var selModel = new Ext.grid.RowSelectionModel({
		singleSelect:true
	});

	var addAction = new Ext.Action({
		text: '追加',
		iconCls: 'addIcon',
		handler: addActionHandler
	});

	var editAction = new Ext.Action({
		text: '編集',
		iconCls: 'editIcon',
		handler: editActionHandler
	});

	var deleteAction = new Ext.Action({
		text: '削除',
		iconCls: 'deleteIcon',
		handler: deleteActionHandler
	});

	var findAction = new Ext.Action({
		text: '検索',
		iconCls: 'findIcon'
	});

	var tbar = [
		addAction,
		'-',
		editAction,
		deleteAction,
		'-',
		findAction
	];

	var pageSize = 20;

	var bbar = new Ext.PagingToolbar({
		id: 'pagingToolbar',
		pageSize: pageSize,
		store: store,
		displayInfo: true,
		displayMsg: '社員の一覧 {2} 件中 {0} - {1} 件目',
		emptyMsg: "社員の一覧はありません"
	});

	var grid = new Ext.grid.GridPanel({
		title:'社員管理',
		stripeRows: true,
		autoExpandColumn: 'name',
		height:523,
		width:600,
		store: store,
		colModel: colModel,
		selModel: selModel,
		tbar: tbar,
		bbar: bbar
	});

	// INIT
	
	grid.render('grid-employee');

	store.load({params:{start:0, limit:pageSize}});

});

employee.jsは以上です。続いて呼び出されるフォームアクションを作成します。ソースは以下の通りです。

EmployeeAction.java
package webapplication.action;

import javax.annotation.Resource;

import org.seasar.framework.beans.util.Beans;
import org.seasar.struts.annotation.ActionForm;
import org.seasar.struts.annotation.Execute;
import org.seasar.struts.util.ResponseUtil;

import webapplication.entity.Employee;
import webapplication.form.EmployeeForm;
import webapplication.service.EmployeeService;


public class EmployeeAction {

	@ActionForm
	@Resource
	protected EmployeeForm employeeForm;

	@Resource
	protected EmployeeService employeeService;

	@Execute(validator = false)
	public String create() {
		Employee entity = Beans.createAndCopy(Employee.class, employeeForm)
				.execute();
		employeeService.insert(entity);
		ResponseUtil.write("{success:true}", "application/json");
		return null;
	}

	@Execute(validator = false)
	public String update() {
		Employee entity = Beans.createAndCopy(Employee.class, employeeForm)
				.execute();
		employeeService.update(entity);
		ResponseUtil.write("{success:true}", "application/json");
		return null;
	}

	@Execute(validator = false)
	public String delete() {
		Employee entity = Beans.createAndCopy(Employee.class, employeeForm)
				.execute();
		employeeService.delete(entity);
		ResponseUtil.write("{success:true}", "application/json");
		return null;
	}

}

以上で実装は完了です。ブラウザでhttp://localhost:8080/ajax-app/employee/index.htmlをアクセスし編集・削除ボタンを実行して確認します。

編集


削除


今回は以上です。

フォームへのデータ読み込み、アクションフォームの呼び出し共に特別な事はしていません。非常に簡単に実装できるのがわかって頂けると思います。

次回はデータの検索を実装します。いよいよ最終回です。