Created
August 17, 2011 09:39
-
-
Save mindscratch/1151201 to your computer and use it in GitHub Desktop.
jqGrid widget using JavaScriptMVC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <table id="<%= options.gridId %>" class="grid <%= options.gridClass %>"> | |
| <tr> | |
| <td /> | |
| </tr> | |
| </table> | |
| <div id="<%= options.pagerId %>"></div> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // JavaScript MVC 3.0.5 | |
| // jQuery 1.6 | |
| // jqGrid 4.0 | |
| steal.plugins('jquery/controller/subscribe', 'jquery/view/ejs') | |
| .views('grid.ejs').then(function($) { | |
| /** | |
| * A grid component that uses data from a local source (i.e. array) as opposed to | |
| * fetching it remotely. | |
| * | |
| * The idea was to let some other part of the application fetch the data and | |
| * then give it to this widget to update the grid, instead of having the grid | |
| * handle making remote calls to the server (to fetch data, sort, page, etc). | |
| */ | |
| $.Controller.extend('MyApp.Widgets.LocalGrid', | |
| { | |
| defaults: { | |
| // the column model | |
| colModel: null, // a column model must be provided | |
| // the default view template | |
| grid: '//myapp/controllers/widgets/grid/views/grid.ejs', | |
| // a CSS class to apply to the <table> element | |
| gridClass: "", | |
| altRowClass: "", | |
| // the ID for the grid | |
| gridId: 'myapp_grid', | |
| // the ID for the pager component | |
| pagerId: 'myapp_grid_pager', | |
| // callback for when a sort operation occurs, is given 3 params: | |
| // - column name | |
| // - column index | |
| // - sort order ('asc', 'desc') | |
| onSort: $.noop, | |
| // callback for when a paging operation occurs, is given 2 params: | |
| // - pager (see jqGrid 'onpaging' docs) | |
| // - page: the page number being asked for | |
| onPage: $.noop, | |
| // provide the object to use as "this" when invoking callbacks | |
| callbackScope: null | |
| } | |
| }, | |
| { | |
| init: function(el) { | |
| this.ignoreSortEvent = false; | |
| this.update(); | |
| }, | |
| update: function(options) { | |
| this._super(options || {}); | |
| this.draw(); | |
| }, | |
| draw: function() { | |
| // render the view | |
| this.element.html(this.options.grid, {options: this.options}); | |
| // add the jqGrid | |
| this.gridEl = this.element.find('#' + this.options.gridId); | |
| this._createGrid(this.gridEl); | |
| }, | |
| /** | |
| * Add a jqGrid to the given element | |
| * | |
| * @param {HtmlElement} el | |
| */ | |
| _createGrid: function(el) { | |
| var self = this, | |
| sortCallback = this.options.onSort, | |
| pageCallback = this.options.onPage, | |
| scope = this.options.callbackScope; | |
| /* a timeout function is used so the grid width will be calculated properly by jqGrid */ | |
| setTimeout(function() { | |
| el.jqGrid({ | |
| altRows: true, | |
| altClass: self.options.altRowClass, | |
| datatype: 'local', | |
| colModel: self.options.colModel, | |
| rowNum: 20, | |
| recordText: "Show {0} - {1} of {2}", | |
| pager: '#' + self.options.pagerId, | |
| viewrecords: true, | |
| gridview: true, | |
| height: '100%', | |
| autowidth: true, | |
| onSortCol: function(index, iCol, sortorder) { | |
| if (self.ignoreSortEvent) { | |
| return "stop"; | |
| } | |
| return sortCallback.apply(scope, arguments); | |
| }, | |
| onPaging: function(type) { | |
| // only handler 'user' paging (e.g. when a user types in a page number). | |
| // the paging buttons are handled by a custom click event handler (see code further down) | |
| var requestedPage = $('.ui-pg-input').val() || '', | |
| last = el.jqGrid('getGridParam', 'lastpage') || 1, | |
| isNumber = requestedPage.match(/^\d+$/), | |
| cp = self.currentPage || 1; | |
| if (!isNumber || last <= 1) { | |
| return false; | |
| } | |
| requestedPage = parseInt(requestedPage, 10); | |
| if (requestedPage === cp || requestedPage < 1 || requestedPage > last) { | |
| return false; | |
| } | |
| return pageCallback.call(scope, this.id, requestedPage); | |
| } | |
| }); | |
| // instead of having "Showing 3 901 - 3 919 of 3919" | |
| // setting the separator to a comma gives us: Showing 3,901 - 3,919 of 3,919 | |
| $.jqgrid.formatter.integer.thousandsSeparator = ','; | |
| /* | |
| * instead of using the 'onPaging' event handler for the grid (it's used for one case) | |
| * we unbind the click event handlers that jqgrid configures and we define our own. | |
| * This is done b/c the jqgrid click handler references a "ts.p.page" to determine whiche | |
| * page to go to, however, it doesn't work properly (meaning it will say the current page | |
| * is 1 even though the user is looking at page 2). | |
| */ | |
| $('#first, #prev, #next, #last').unbind('click').bind('click', function(e) { | |
| var cp = self.currentPage || 1, | |
| last = el.jqGrid('getGridParam', 'lastpage') || 1, | |
| requestedPage = -1, | |
| selclick = false, | |
| fp = true, | |
| pp = true, | |
| np = true, | |
| lp = true; | |
| if (last === 0 || last === 1) { | |
| fp = pp = np = lp = false; | |
| } | |
| else if (last > 1 && cp >= 1) { | |
| if (cp === 1) { | |
| fp = pp = false; | |
| } | |
| else if (cp > 1 && cp < last) { | |
| } | |
| else if (cp === last) { | |
| np = lp = false; | |
| } | |
| } | |
| else if (last > 1 && cp === 0) { | |
| np = lp = false; | |
| cp = last - 1; | |
| } | |
| if (this.id === 'first' && fp) { requestedPage = 1; selclick = true; } | |
| if (this.id === 'prev' && pp) { requestedPage = (cp - 1); selclick = true; } | |
| if (this.id === 'next' && np) { requestedPage = (cp + 1); selclick = true; } | |
| if (this.id === 'last' && lp) { requestedPage = last; selclick = true; } | |
| if (selclick) { | |
| return pageCallback.call(scope, this.id, requestedPage); | |
| } | |
| }); | |
| }, 30); | |
| }, | |
| /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| * | |
| * API Methods | |
| * | |
| * These methods ar emeant to be invoked by users/clients of this code. | |
| * | |
| * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| */ | |
| /** | |
| * Set the data for the grid. | |
| * | |
| * @param {Object} data the data for the grid, this should contain the following properties: | |
| * - rows: array of objects, one per row | |
| * - page: the page number of this dataset (1-based, so page 1,2,3. Not page, 0,1,2). | |
| * - total: the total number of pages available | |
| * - records: the number of records available | |
| * - sidx: the name of the column to sort | |
| * - sord: the sort order, either 'asc' or 'desc' | |
| */ | |
| setData: function(data) { | |
| this.currentPage = data.page; | |
| var self = this, | |
| reader = { | |
| root: function(obj) { return data.rows; }, | |
| page: function(obj) { return data.page; }, | |
| total: function(obj) { return data.total; }, | |
| records: function(obj) { return data.records; }, | |
| repeatItems: false | |
| }; | |
| this.gridel.jqGrid('setGridParam', { | |
| data: data.rows, | |
| localReader: reader, | |
| sortname: String(data.sidx), | |
| sortorder: data.sord, | |
| page: data.page | |
| }).trigger('reloadGrid'); | |
| // update the sort icons in the columns | |
| setTimeout(function() { | |
| self.updateSortIcons(data.sidx, data.sord); | |
| }, 50); | |
| }, | |
| updateSortIcons: function(columnName, sortorder) { | |
| this.ignoreSortEvent = true; | |
| this.gridEl.sortGrid(String(columnName), false, sortorder); | |
| this.ignoreSortEvent = false; | |
| }, | |
| redraw: function() { | |
| this.gridEl.trigger('reloadGrid'); | |
| } | |
| }) | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment