NHibernate3.2+Asp.net MVC3+Extjs 4.0.2项目实践(六):Extjs Grid,Window,Form实现增删改操作
上一节讲到利用树形菜单的打击事件来动态加载Tab(继承自Ext.Panel)页,那Tab页如何来装载Grid,并实现数据浏览及增删改操作呢?原理是这样的:Tab页中autoLoad属性的url定义为Controller的Action方法,来render一个MVC view到Tab Panel,而view装载的是GridPanel的Extjs组件,这个组件并不是自定义组件(非define),而是直接用Ext.create来创建的,可能因为涉及到Grid的操作比较多;这里有一个宽度自适应问题,就是当浏览器resize的时候,GridPanel的宽度如何来自适应,方法是定义Tab Panel的resize事件来控制GridPanel的宽度,可以参考上一节贴出的代码。
接下来看一下Controller:
CountryController.cspublic partial class AppCenterController : Controller
{
//
// GET: /Country/
public ActionResult CountryPage()
{
return PartialView("~/Views/AppCenter/_Country.cshtml");
}
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult CountryList()
{
var result = _iLocation_CountryService.GetLocation_Countries();
var ts = from t in result
select new { t.CountryId, t.CountryName, t.CountryCode1, t.CountryCode2, t.CountryDialCode, t.ModifiedDate, t.ModifiedBy };
int total = result.Count;
//var tss = result.AsQueryable().ToList();
return Json(new { Countries = ts, totalCount = total }, JsonRequestBehavior.AllowGet);
}
[HttpPost]
public JsonResult CreateCountry(Location_Country country)
{
try
{
country.ModifiedBy = ADHelper.ToADAccountName(User.Identity.Name);
country.ModifiedDate = DateTime.Now;
if (_iLocation_CountryService.CreateLocation_Country(country))
{
return Json(new { success = true, Msg = "Add country successfully." });
}
else
{
return Json(new { success = false, Msg = "Failed to add country." });
}
}
catch
{
return Json(new {success=false, Msg ="Unkown error occurred while adding country." });
//return Json(new { success = false, Msg = "Unkown error:</br>" + "Source:" + ex.TargetSite.Name + "</br> Error:" + ex.Message });
}
}
[HttpPost]
public JsonResult UpdateCountry(Location_Country country)
{
try
{
Location_Country lc = _iLocation_CountryService.FindLocation_Country(Data.DataAccess.Country_Query_Index.CountryId, country.CountryId);
country.ModifiedDate = lc.ModifiedDate;
country.ModifiedBy = lc.ModifiedBy;
if (_iLocation_CountryService.UpdateLocation_Country(country))
{
return Json(new { success = true, Msg = "Update country successfully." });
}
else
{
return Json(new { success = false, Msg = "Failed to update country." });
}
}
catch
{
return Json(new { success = false, Msg = "Unkown error occurred while updating country." });
}
}
[HttpPost]
public JsonResult DeleteCountries(Array countries)
{
var message="";
int iUpdates=0;
try
{
foreach (object o in countries)
{
Location_Country lc = _iLocation_CountryService.FindLocation_Country(Data.DataAccess.Country_Query_Index.CountryId, Convert.ToInt32(o));
if (_iLocation_CountryService.DeleteLocation_Country(lc))
iUpdates += 1;
}
message = iUpdates.ToString() + " countries deleted successfully.";
return Json(new { success = true, Msg = message });
}
catch
{
message = "Error occurred while deleting countries and "+iUpdates.ToString()+" countries deleted.";
return Json(new { success = false, Msg = message });
}
}
}
CountryController.cs中定义了partialView,CountryList,Create,Update和Delete的Action。
<script src="@Url.Content("~/Components/Tesz.App/Pages/Country.js")" type="text/javascript"></script>
<div id="divCountry"></div>
以上是View文件_Country.cshtml。
Country.jsExt.require('Tesz.App.Models.CountryModel');
Ext.require('Tesz.App.Stores.CountryStore');
var store;
Ext.onReady(function () {
store = Ext.create('Tesz.App.Stores.CountryStore');
LoadGridData();
var refreshAction = Ext.create('Ext.Action', {
iconCls: 'x-tbar-loading',
text: 'Refresh',
handler: LoadGridData
});
var addAction = Ext.create('Ext.Action', {
iconCls: 'x-toolbarbtn-add',
text: 'Add new item',
handler: function () {
openCTRYWindow('Add');
}
});
var deleteAction = Ext.create('Ext.Action', {
iconCls: 'x-toolbarbtn-delete',
text: 'Delete item',
disabled: true,
handler: function () {
Ext.MessageBox.confirm('Message', 'Sure to delete selected items?', function (e) {
if (e == 'no') {
return;
}
else {
DeleteCounties();
}
});
}
});
var gridCountry = Ext.create('Ext.grid.Panel', {
renderTo: 'divCountry',
requires:['Tesz.App.SearchField'],
id: 'COUNTRYGRID',
height: 350,
store: store,
frame: true,
selModel: Ext.create('Ext.selection.CheckboxModel'),
columns: [{
text: "Id",
dataIndex: 'CountryId',
width: 50,
sortable: true
}, {
text: "Name",
dataIndex: 'CountryName',
width: 150
}, {
text: "Code1",
dataIndex: 'CountryCode1',
width: 100
}, {
text: "Code2",
dataIndex: 'CountryCode2',
width: 100
}, {
text: "Dial Code",
dataIndex: 'CountryDialCode',
width: 100
}, {
text: "Modified Date",
dataIndex: 'ModifiedDate',
renderer: renderTime,
width: 150
}, {
text: "Modified By",
dataIndex: 'ModifiedBy',
flex: 1
}],
dockedItems: [{
xtype: 'toolbar',
//store: store, // same store GridPanel is using
dock: 'bottom',
height: 26,
items: [refreshAction, '-', {
text: 'Total 0 records.',
id: 'tbarCount'
}]
}, {
xtype: 'toolbar',
dock: 'top',
items: [addAction, '-', deleteAction, '-', exportAction]
}],
listeners: {
itemdblclick: function (grid, rec, item, index, e) {
openCTRYWindow('Edit');
var form = Ext.getCmp('COUNTRYFORM');
form.loadRecord(rec);
//alert(form.id);
}
}
});
gridCountry.getSelectionModel().on({
selectionchange: function (sm, selections) {
if (selections.length) {
deleteAction.enable();
} else {
deleteAction.disable();
}
}
});
});
function openCTRYWindow(action) {
var window = Ext.getCmp('COUNTRYWINDOW');
if (!window)
window = Ext.create('Tesz.App.Forms.CountryForm');
window.setTitle(action);
if (action == 'Add') {
var form = Ext.getCmp('COUNTRYFORM');
form.form.reset();
}
window.show();
}
function LoadGridData() {
store.load({
callback: function (records, options, success) {
//var total = store.getCount();
//totalRecordCount = records.length;
//alert(records.length);
var tbar = Ext.getCmp('tbarCount');
tbar.setText('Total ' + records.length + ' records.');
}
});
}
function DeleteCounties() {
var grid = Ext.getCmp('COUNTRYGRID');
var records = grid.getSelectionModel().getSelection();
var array=new Array(records.length);
for (var i = 0; i < records.length; i++) {
array[i] = records[i].get('CountryId');
}
Ext.Ajax.request({
url: 'DeleteCountries', //请?求ó的?Action
method: "POST",
params: { countries: array }, //发¢送í的?参?数y
success: function (r, p) {
var o = Ext.decode(r.responseText);
try {
Ext.MessageBox.alert("Message", o.Msg, LoadGridData);
}
catch (e) {
Ext.MessageBox.alert("Unkown error", e);
}
},
failure: function (r, p) {
try {
Ext.MessageBox.alert("Error", o.Msg);
}
catch (e) {
Ext.MessageBox.alert("Unkown error", e);
}
}
});
}
Country.js是View文件装载的GridPanel的js组件,定义了GridPanel的toolbar、toolbar buttons及事件;GridPanel的itemdblclick及selectionchange事件;还有LoadGridData,DeleteCounties方法。toolbar buttons包括Add,Delete和Refresh,继承自Ext.Action;通过点击Add按钮,打开一个内嵌FormPanel的Window来执行数据记录的添加,或由GridPanel的itemdblclick事件打开,两个事件以标识所打开Window的Title为”Add”,”Edit”来区分是添加还是修改操作。GridPanel的selectionchange事件响应Delete按钮的Enable和Disable;LoadGridData实现GridPanel数据的刷新。DeleteCounties方法通过GridPanel的selectionchange事件响应的grid.getSelectionModel().getSelection()获取选中的记录Id的Array作为参数Post给Controller的Delete action;
Add,Modify,Delete事件结果通过Ext.MessageBox来通知,并加入了错误处理及提示。
Country.js所引用的Store,Model如下:
CountryStore.jsExt.define('Tesz.App.Stores.CountryStore', {
extend: 'Ext.data.Store',
requires: ['Tesz.App.Models.CountryModel'],
alias: 'widget.countrystore',
//model: 'stateprovincemodel',
model: 'Tesz.App.Models.CountryModel',
//pageSize: 20,
proxy: {
type: 'ajax',
url: 'CountryList',
reader: {
type: 'json',
root: 'Countries',
totalProperty: 'totalCount',
id: 'CountryId'
}
}
});
Ext.define('Tesz.App.Models.CountryModel', {
extend: 'Ext.data.Model',
alias: 'widget.countrymodel',
idProperty: 'CountryId',
fields: ['CountryId', 'CountryName', 'CountryCode1', 'CountryCode2', 'CountryDialCode', 'ModifiedDate', 'ModifiedBy']
});
最后就是记录的添加和修改操作了,通过FormPanel的form.submit()实现;Open Window时如果为”Add”操作,用form.reset()来清空Fields,为”Edit”时用form.loadRecord(rec)方法装载Fields。submit时以Window的Title为依据来定义submit的url指向controller的action,submit前先对Fields进行合法性验证。代码如下:
CountryForm.jsvar countryform = Ext.create('Ext.form.Panel', {
frame: true,
id: 'COUNTRYFORM',
monitorValid: true,
bodyStyle: 'padding:5px 5px 0',
fieldDefaults: {
labelAlign: 'top',
msgTarget: 'side'
},
items: [{
xtype: 'container',
anchor: '100%',
layout: 'column',
items: [{
xtype: 'container',
columnWidth: .5,
layout: 'anchor',
items: [{
xtype: 'textfield',
name: 'CountryId',
value: 0,
hidden: true
},{
xtype: 'textfield',
fieldLabel: 'Country Name',
name: 'CountryName',
allowBlank: false,
maxLength: 50,
anchor: '96%'
}, {
xtype: 'textfield',
fieldLabel: 'Country Code1',
name: 'CountryCode1',
maxLength: 10,
anchor: '96%'
}]
}, {
xtype: 'container',
columnWidth: .5,
layout: 'anchor',
items: [{
xtype: 'textfield',
fieldLabel: 'Country Code2',
name: 'CountryCode2',
maxLength: 10,
anchor: '100%'
}, {
xtype: 'textfield',
fieldLabel: 'Dial Code',
name: 'CountryDialCode',
maxLength: 10,
anchor: '100%'
}]
}]
}],
buttons: [{
text: 'Save',
formBind: true,
handler: SubmitForm
}, {
text: 'Cancel',
handler: CloseWindow
}]
});
Ext.define('Tesz.App.Forms.CountryForm', {
extend: 'Ext.Window',
id:'COUNTRYWINDOW',
title: 'Country Edit',
width: 600,
height: 400,
iconCls: 'x-window-icon',
plain: true,
constrain: true,
closeAction: 'hide',
layout:'fit',
modal: true,
items: countryform
});
function SubmitForm() {
if (!countryform.form.isValid()) {
return;
}
var win = Ext.getCmp('COUNTRYWINDOW');
var actionUrl;
if (win.title == 'Add') {
actionUrl = 'CreateCountry';
}
else {
actionUrl = 'UpdateCountry';
}
countryform.form.submit({
waitMsg: "Submitting data to server...",
url: actionUrl,
success: function (f, a) {
try {
Ext.MessageBox.alert("Message", a.result.Msg, RefreshCountryGrid);
}
catch (e) {
Ext.MessageBox.alert("Unkown error", e);
}
},
failure: function (f, a) {
try {
Ext.MessageBox.alert("Error", a.result.Msg);
}
catch (e) {
Ext.MessageBox.alert("Unkown error", e);
}
}
});
}
function CloseWindow() {
var win = Ext.getCmp('COUNTRYWINDOW');
win.hide();
}
function RefreshCountryGrid() {
var grid = Ext.getCmp('COUNTRYGRID');
grid.getStore().load({
callback: function (records, options, success) {
//var total = store.getCount();
//totalRecordCount = records.length;
//alert(records.length);
var tbar = Ext.getCmp('tbarCount');
tbar.setText('Total ' + records.length + ' records.');
}
});
CloseWindow();
}