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.cs public 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.js
Ext.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 usingdock: '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 }, //发¢送í的?参?数ysuccess: 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.js
Ext.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'}}
});
CountryModel.js
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.js
var 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();
}
浙公网安备 33010602011771号