Someone recently requested me to send me the sample asp.net application using MVC ExtJS and LINQ.
Here is the application with our infamous northwind database and Categories table.
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Script.Serialization; using Northwind; namespace Controllers { public class CategoryController : Controller { public ActionResult Index() { ViewData["Title"] = "Category Page"; ViewData["Message"] = "Welcome to Category Page!"; return View(); } public void LoadCategory() { int id = int.Parse(Request.Form["id"]); string message = string.Empty; NorthwindDataContext db = new NorthwindDataContext(); var query = from c in db.Categorys where c.CategoryID == id select new { c.CategoryID, c.CategoryName, c.Description, c.Picture }; JavaScriptSerializer serializer = new JavaScriptSerializer(); message = "{\"results\":" + serializer.Serialize(query.ToList()) + "}"; Response.Write(message); } public void ListCategory(int limit, int start, string dir, string sort) { string message = string.Empty; NorthwindDataContext db = new NorthwindDataContext(); var query = from c in db.Categorys select new { c.CategoryID, c.CategoryName, c.Description, c.Picture }; int totalRecords = query.ToList().Count; JavaScriptSerializer serializer = new JavaScriptSerializer(); var list = query.Skip(start).Take(limit); message = "{\"total\": \"" + totalRecords + "\", \"results\":" + serializer.Serialize(list.ToList()) + "}"; Response.Write(message); } public void New() { Category _Category = new Category(); string _CategoryID = Request.Form["CategoryID"]; if(_CategoryID != null && _CategoryID != string.Empty) { _Category.CategoryID = int.Parse(_CategoryID); } string _CategoryName = Request.Form["CategoryName"]; if(_CategoryName != null && _CategoryName != string.Empty) { _Category.CategoryName = _CategoryName; } string _Description = Request.Form["Description"]; if(_Description != null && _Description != string.Empty) { _Category.Description = _Description; } string _Picture = Request.Form["Picture"]; if(_Picture != null && _Picture != string.Empty) { _Category.Picture = null; } NorthwindDataContext db = new NorthwindDataContext(); try { db.Categorys.InsertOnSubmit(_Category); db.SubmitChanges(); } catch (Exception ex) { string error = ex.Message; //log the error here } } public void Edit() { int id = int.Parse(Request.Form["id"]); NorthwindDataContext db = new NorthwindDataContext(); Category obj = db.Categorys.Single<category></category>(c => c.CategoryID == id); string _CategoryName = Request.Form["CategoryName"]; if(_CategoryName != null && _CategoryName != string.Empty) { obj.CategoryName = _CategoryName; } string _Description = Request.Form["Description"]; if(_Description != null && _Description != string.Empty) { obj.Description = _Description; } string _Picture = Request.Form["Picture"]; if(_Picture != null && _Picture != string.Empty) { obj.Picture = null; } try { db.SubmitChanges(); } catch (Exception ex) { string error = ex.Message; //log the error here } } public void Delete() { NorthwindDataContext db = new NorthwindDataContext(); string data = Request.Form["data"]; foreach (object o in data.Split(',')) { int id = int.Parse(o.ToString()); Category obj = db.Categorys.Single<category></category>(c => c.CategoryID == id); db.Categorys.DeleteOnSubmit(obj); } db.SubmitChanges(); } } }
namespace Northwind { using System.Data.Linq; using System.Data.Linq.Mapping; using System.Data; using System.Collections.Generic; using System.Reflection; using System.Linq; using System.Linq.Expressions; using System.ComponentModel; using System; [System.Data.Linq.Mapping.DatabaseAttribute(Name="Northwind")] public partial class NorthwindDataContext : System.Data.Linq.DataContext { private static System.Data.Linq.Mapping.MappingSource mappingSource = new AttributeMappingSource(); #region Extensibility Method Definitions partial void OnCreated(); partial void InsertCategory(Category instance); partial void UpdateCategory(Category instance); partial void DeleteCategory(Category instance); #endregion public NorthwindDataContext() : base(global::System.Configuration.ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString, mappingSource) { OnCreated(); } public NorthwindDataContext(string connection) : base(connection, mappingSource) { OnCreated(); } public NorthwindDataContext(System.Data.IDbConnection connection) : base(connection, mappingSource) { OnCreated(); } public NorthwindDataContext(string connection, System.Data.Linq.Mapping.MappingSource mappingSource) : base(connection, mappingSource) { OnCreated(); } public NorthwindDataContext(System.Data.IDbConnection connection, System.Data.Linq.Mapping.MappingSource mappingSource) : base(connection, mappingSource) { OnCreated(); } public System.Data.Linq.Table<category></category> Categorys { get { return this.GetTable<category></category>(); } } } }
<asp:content contentplaceholderid="MainContent" runat="server" id="indexContent"> <h2><!--Html.Encode(ViewData["Message"])--></h2> <script type="text/javascript"> Ext.BLANK_IMAGE_URL = '../../resources/images/default/s.gif'; Ext.namespace('myNameSpace'); myNameSpace.myModule = function(){ var ds; var grid; var colModel; var myRecordObj; var myReader; var primaryKey='CategoryID'; var setupDataSource = function(){ myRecordObj = Ext.data.Record.create([ {name: 'CategoryID', type: 'int'}, {name: 'CategoryName', type: 'string'}, {name: 'Description', type: 'string'}, {name: 'Picture', type: 'string'} ]); myReader = new Ext.data.JsonReader( { root: 'results', totalProperty: 'total', id: primaryKey }, myRecordObj ); ds = new Ext.data.GroupingStore({ proxy: new Ext.data.HttpProxy({ url: '/Category/ListCategory', method: 'POST' }), reader: myReader, remoteSort: true }); };//end setupDataSource var getColumnModel = function() { if(!colModel) { colModel = new Ext.grid.ColumnModel([ { header: 'CategoryID', dataIndex: 'CategoryID', sortable: true, width: 50 }, { header: 'CategoryName', dataIndex: 'CategoryName', sortable: true, width: 50 }, { header: 'Description', dataIndex: 'Description', sortable: true, width: 50 }, { header: 'Picture', dataIndex: 'Picture', sortable: true, width: 50 } ]);//end colModel }//end if colModel return colModel; }//end getColumnModel var buildGrid = function(){ function addRecord() { var c_CategoryID = new Ext.form.NumberField ({ fieldLabel: 'CategoryID', name: 'CategoryID', width: '180', allowDecimals: true, allowNegative: false, blankText: '0', maxLength: 19 }); var c_CategoryName = new Ext.form.TextField ({ fieldLabel: 'CategoryName', name: 'CategoryName', width: '180', maskRe: /([a-zA-Z0-9\s]+)$/ }); var c_Description = new Ext.form.TextArea ({ fieldLabel: 'Description', name: 'Description', width: '180', hideLabel: false }); var c_Picture = new Ext.form.TextField ({ fieldLabel: 'Picture', name: 'Picture', width: '180', maskRe: /([a-zA-Z0-9\s]+)$/ }); var newForm = new Ext.FormPanel({ bodyStyle: 'padding: 8px', url:'/Category/New', items: [ c_CategoryID, c_CategoryName, c_Description, c_Picture ] }); var newWin = new Ext.Window({ title: 'Add a new Category', width: 390, height:500, minWidth: 300, minHeight: 250, layout: 'fit', plain:true, bodyStyle:'padding:5px;', buttonAlign:'center', items: newForm, buttons: [{ text: 'Save', handler: function() { if (newForm.form.isValid()) { newForm.form.submit({ waitMsg:'In processing', failure: function(form, action) { Ext.MessageBox.alert('Error Message', action.result.errorInfo); }, success: function(form, action) { Ext.MessageBox.alert('Success:', action.response.responseText); refreshGrid(); newWin.hide(); } }); } else { Ext.MessageBox.alert('Errors', 'Please fix the errors noted.'); } } },{ text: 'Clear', handler: function(){ newForm.getForm().reset(); } }] }); newWin.on('minimize', function(){ newWin.toggleCollapse(); }); newWin.show(); };// end addRecord function deleteRecord(btn) { if(btn=='yes') { var selectedKeys = grid.selModel.selections.keys; Ext.Ajax.request({ waitMsg: 'Saving changes...', url: '/Category/Delete', params: { data: selectedKeys }, callback: function (options, success, response) { if (success) { Ext.MessageBox.alert('OK',response.responseText); var json = Ext.util.JSON.decode(response.responseText); Ext.MessageBox.alert('OK',json.del_count + ' record(s) deleted.'); } else{ Ext.MessageBox.alert('Sorry, please try again. [Q304]',response.responseText); } }, failure:function(response,options){ Ext.MessageBox.alert('Warning','Oops...'); }, success:function(response,options){ refreshGrid(); } }); } }; function handleDelete() { var selectedKeys = grid.selModel.selections.keys; if(selectedKeys.length > 0) { Ext.MessageBox.confirm('Message','Do you really want to delete selection?', deleteRecord); } else { Ext.MessageBox.alert('Message','Please select at least one item to delete'); } }; // end handleDelete function toggleDetails(btn, pressed){ var view = grid.getView(); view.showPreview = pressed; view.refresh(); } function refreshGrid() { ds.reload(); // }; grid = new Ext.grid.GridPanel({ clicksToEdit:2, colModel: getColumnModel(), height:350, //iconCls: 'icon-grid', id: 'myGridID', loadMask: true, selModel: new Ext.grid.RowSelectionModel({singleSelect:false}), store: ds, stripeRows: true, title:'Category List', width:600, bbar: new Ext.PagingToolbar({ pageSize: myNameSpace.myModule.perPage, store: ds, displayInfo: true, displayMsg: 'Displaying topics {0} - {1} of {2}', emptyMsg: "No data to display", items:[ '-', { pressed: true, enableToggle:true, text: 'Show Preview', cls: 'x-btn-text-icon details', toggleHandler: toggleDetails }] }), tbar: [ { text: 'Add', tooltip: 'Click to Add a row', //iconCls:'add', handler: addRecord }, '-', //add a separator { text: 'Delete', tooltip: 'Click to Delete selected row(s)', //function to call when user clicks on button //iconCls:'remove', handler: handleDelete }, '-', { text: 'Refresh', tooltip: 'Click to Refresh the table', //iconCls:'refresh', handler: refreshGrid } ], view: new Ext.grid.GroupingView({ forceFit:true, groupTextTpl: '{text} ({[values.rs.length]} {[values.rs.length > 1 ? "Items" : "Item"]})' }) });//end grid grid.on('rowdblclick', function(grid, rowIndex, e) { var id = ds.data.items[rowIndex].id; var u_CategoryID = new Ext.form.NumberField ({ fieldLabel: 'CategoryID', name: 'CategoryID', width: '180', allowDecimals: true, allowNegative: false, blankText: '0', maxLength: 19 }); var u_CategoryName = new Ext.form.TextField ({ fieldLabel: 'CategoryName', name: 'CategoryName', width: '180', maskRe: /([a-zA-Z0-9\s]+)$/ }); var u_Description = new Ext.form.TextArea ({ fieldLabel: 'Description', name: 'Description', width: '180', hideLabel: false }); var u_Picture = new Ext.form.TextField ({ fieldLabel: 'Picture', name: 'Picture', width: '180', maskRe: /([a-zA-Z0-9\s]+)$/ }); var updateForm = new Ext.FormPanel({ bodyStyle: 'padding: 8px', url:'/Category/Edit', reader: new Ext.data.JsonReader( { root: 'results'}, [ {name: 'CategoryID', type: 'int'}, {name: 'CategoryName', type: 'string'}, {name: 'Description', type: 'string'}, {name: 'Picture', type: 'string'} ]), items: [ u_CategoryID, u_CategoryName, u_Description, u_Picture ] }); updateForm.form.load({ url:'/Category/LoadCategory', params: { id: id }, waitMsg:'Loading' }); var window = new Ext.Window({ title: 'Edit Existing Category', width: 390, height:500, minWidth: 300, minHeight: 250, layout: 'fit', plain:true, bodyStyle:'padding:5px;', buttonAlign:'center', items: updateForm, buttons: [{ text: 'Save', handler: function() { if (updateForm.form.isValid()) { updateForm.form.submit({ params:{id : id}, waitMsg:'In processing', failure: function(form, action) { Ext.MessageBox.alert('Error Message', action.result.errorInfo); }, success: function(form, action) { Ext.MessageBox.alert('Confirm', action.response.responseText); window.hide(); ds.load({params:{start:0, limit:10}}); } }); } else{ Ext.MessageBox.alert('Errors', 'Please fix the errors noted.'); } } }, { text: 'Cancel', handler: function(){window.hide();} }] }); window.show(); }); }//end function buildGrid var renderGrid = function() { grid.render('CustomersList'); }; //end function renderGrid var loadStore = function() { ds.load({ params: { start: 0, limit: myNameSpace.myModule.perPage } }); grid.getSelectionModel().selectFirstRow(); }; return { perPage: 10, init : function(){ this.getMyGrid(); }, //end of init method getMyGrid: function() { Ext.QuickTips.init(); setupDataSource(); buildGrid(); renderGrid(); loadStore(); }, getDataSource: function() { return ds; } }//end of return }(); Ext.onReady(myNameSpace.myModule.init, myNameSpace.myModule, true); </script> </asp:content>
Northwind.Category.model.cs
Northwind.Category.Controller.cs
Northwind.Category.view.aspx
Popularity: 13% [?]



Mohammed,
Thank you so much for this wonderful example! I recently started an ASP.NET MVC app with ExtJS and this is exactly what I was looking for. The ExtJS code is great. I really like the way it is formatted and written. Very easy to understand.
Keep up the excellent work!!
Alan,
Thank you. I’m glad you found this article helpful.
Thanks
Mohammed,
I’m hoping that you might be able to assist me with a problem I’m running into. I’m trying to adapt your code from above to include 2 grids so that I can enable drag and drop (much like the example here: http://extjs.com/deploy/dev/examples/dd/dnd_grid_to_grid.html)
Any guidance or advice you have would be greatly, greatly appreciated. Thanks!!
Alan
How far are you in simulating that drag and drop in your code ?