JQuery Plugin: serializeCFJSON

Quick note about my serializeCFJSON project out on GitHub. I wrote this quick JQuery plugin to convert ColdFusion's JSON representation of it's native query objects. ColdFusion represents datasets in a trim manner, as an object containing two arrays: One, an array of column names, and the other, an array of arrays, each representing one record of the set. Most representations of recordsets are an array of objects, each record represented as a collection of name/value pairs. ColdFusion's representation is much smaller, removing a lot of unnecessary duplication, but many pre-built frameworks and plugins look for the name/value pair objects.

What the plugin does is convert ColdFusion's representation into the more standard form. Ajax transfer is unaffected, as the trimmer format is still being passed. What we get is some very minor client-side overhead in the creation of a new object. What's more, the plugin recursively searches through a JSON object and converts any ColdFusion query that it finds. So, if you nest your query inside a larger object, the plugin will still convert it for you.

I put up a demo in the Projects menu, at the top of this site. This is a refactor of my Grouped jqGrid example, using the plugin for the data conversion. The full sample code for the demo can be found in the GitHub repository.

Take her out for a spin, and let me know what you think.

Intro to jqGrid Part 7: Grouping

OK, I know I said I was done, but I kept playing around and figured I should share. jqGrid, like other (read: Ext JS) good grid implementations, has the ability to group your data. What does that mean exactly? Well, let's look at our demo for inspiration. We've created a grid of blog post entries. Entries have associated Categories. We can reconfigure our grid to show the entries grouped by Category, with Category headers and accordion like separation.

[More]

Intro to jqGrid Part 6: The Action Column

So far we've covered the base grid configuration, populating the grid with remote data, controlling layout by refining the column model, and given an example of event handling by binding a search form to our grid. This covers most of what the average developer might need to know about working with jqGrid, but I've been promising to tell you how to work with the icons we setup in our action column.

[More]

The Joys of Developing for Internet Explorer

Note: Follow the madness here to it's conclusion, to discover yet another "Really? I didn't know that..." IE moment, that may save you heartache and pain.

Is the sarcasm evident in my title? It should be. While Internet Explorer may have been "groundbreaking" when it was released, it has ever been the bain of the web developer's existance. Why, you ask? Because it refuses to adhere to standards, and just operates differently than everyone else. To be fair, Internet Explorer 10 is in the works, and supposedly closes the gap a fair amount (and even wins out in some of the html 5/css 3 support), and 7, 8 and 9 did progressively improve (if slowly). Unfortunately the fact remains that some companies/organizations/governments are stuck on Internet Explorer 6, or maybe even 7. If you are a web developer, and write cross-browser web applications, chances are Internet Explorer has hit you more than once in your career.

It's the dumbest things that hit you too. The most obscure "WTF!?!" moments that drive you crazy. That is a daily experience for me now.

[More]

Intro to jqGrid Part 5: Search

At this point we've created a basic grid, filled it with data, refined the display of our columns and added event handlers to handle multiselect options. We've used custom cell formatters, used a custom datatype function, and even added and populated a toolbar in the process. Now let's start looking at some things that aren't necessarily jqGrid specific, but incorporate them for use in our grid. How about a search?

jqGrid includes some things for doing data search, that will automatically build modal windows and stuff. But sometimes you want to format things your own way, or incorporate jqGrid for use within an existing interface. One of the advantages for us, using the datatype function, is that we can preprocess our postdata prior to the ajax request.

[More]

Intro to jqGrid Part 4: Event Handling

By now our demo is really beginning to flesh out a bit. You've probably created your own grid, read through some of the extensive documentation, and started to figure a few things out on your own. In our series, we've created a basic grid, populated it with remote data, and refined our column configuration a bit. This is a lot of information, encompassing in depth explanations on many key basic grid configuration options, writing our paging query, ajax data handling, and more. Now, let's get into some 'grid' stuff that might not be so obvious.

Toolbars

First, we're going to set ourselves up for the future. We're going to want to see some data, but in order to do so we're going to need some buttons to click on. This is a good time to talk about jqGrid's toolbar implementation. jqGrid makes it easy to add toolbars to it's display, but it's a bit of a departure from standard JQuery plugin behavior, as it doesn't allow you to create a toolbar from an existing DOM element, so you have to use script to define and create your toolbar and it's associated elements. The first thing you have to do is add the configuration attribute to your jqGrid config object:

jqGridDemo.js - Toolbar Config

view plain print about
1grid.jqGrid({
2    ...
3    toolbar:[true,"top"],
4    ...
5});

The toolbar config option takes a two element array for an argument. The first (boolean) element enables the toolbar. The second element defines the toolbar's placement. This value can be "top", "bottom" or "both". Adding this configuration attribute will cause jqGrid to automatically create a div for each toolbar defined. It uses a specific naming convention, every time, to create the toolbars: top - "t_" + grid element's id, bottom - "tb_" + grid element's id (i.e.: "t_gridTest"). If you ran your template now, you would see that an empty toolbar has been added to your grid display:

Now that we have a toolbar, we need to add some buttons. JQueryUI has a button object, for nice consistent buttons, so we'll create the DOM elements needed on the toolbar first, then make them into JQUI buttons.

jqGridDemo.js - Toolbar Buttons

view plain print about
1$('#t_gridTest').append('<button id=\"addButton\">Add</button><button id=\"exportButton\">Export</button>').addClass('customToolbar');

jqGridDemo.js - JQUI Buttons

view plain print about
1$('button#addButton').button({icons: {primary: 'add'}}).click(function(ev){
2    ev.preventDefault();
3    
4    return false;
5});
6
7$('button#exportButton').button({icons: {primary: 'page_white_go'}, disabled: true}).click(function(ev){
8    ev.preventDefault();
9    
10    return false;
11});

Here we've created an Add and an Export button on our toolbar, while also adding a new CSS class (customToolbar). Then I made JQUI buttons of our new toolbar buttons, applying appropriate icon classes (defined in our css file). I've also disabled the Export button for the moment, but we'll go into that later.

OK, now we have a toolbar with some nice, pretty buttons on it, let's start talking about some more grid-centric things, like selection models. Data grids serve a wide range of purposes. In the basic model, we were just viewing data, even if we did allow for sorting and paging. We could've just created a table in DOM and used jqGrid's tableToGrid method to make a simple view table. But, chances are you're writing a Data Grid implementation to interact with data. And a common action is to select a record (or records) to interact with.

Multiselect

There are, essentially, three types of selection actions with a Data Grid: individual record selection, multiple record selection, and specific cell selection. The act of any of these selections is an event, and jqGrid includes the ability to add custom Event Handlers directly to the grid configuration. In our implementation, I want to show working with multiple selections, so we need to add a few configuration options. First, let's setup for multiselection:

jqGridDemo.js - Multiselect Configuration

view plain print about
1grid.jqGrid({
2    ...
3    multiselect: gridMultiSelect >
0,
4    multiselectWidth: 25,
5    ...
6});

These are direct grid configuration options. The first, multiselect, is a boolean value that, if true, will automatically create a column of checkboxes on our grid. The second option, multiselectWidth, defines the width of that checkbox column. Notice that I've tied the multiselect attribute to the gridMultiSelect global variable I added a few posts back. If we change that global variable now (gridMultiSelect = 1) you will see it's effects when you reload the page.

And now we have checkboxes for multiple record selection. The user can select, or deselect, records at will, or even 'select all' by clicking the checkbox in the header column (NOTE: this only selects all currently loaded records in the grid). That gridMultiSelect variable is also an offset value, when calculating column positions in our JSON remapping. The inclusion of the checkbox column (multiselect) requires us to shift our positions by one space.

Now there are two things we have to think about: 1) What do we do when a user clicks a row (or selects 'all')? and 2) How do we know what's been selected?

Well, there are all kinds of things you can do with the records selected. What we'll talk about, in our example, is correcting a small issue with jqGrid itself. Let me explain. jqGrid keeps an array of id's, for all selected records, in the read-only grid attribute selarrrow. You can programmatically access those at any time by grabbing that variable from jqGrid.

view plain print about
1grid.jqGrid('getGridParam','selarrrow');

Id's

But if you play with it a bit you'll discover a few things. The first thing you'll figure out is that we aren't (yet) getting the ID of our records, getting a generic rowcount for our id instead. This is because we've used the function datatype, and remapped our JSON to our column configuration, so the id attribute of the jsonReader is basically being ignored. (I've presented a fix for this to the jqGrid team, which they will hopefully implement in the future.) For this reason, we have to set a key in our column model. This will setup an internal keyIndex variable that jqGrid uses in it's processes. Under normal circumstances, the key attribute would be defined on your ID column in the column model. When remapping JSON output, though, this isn't how this would be accomplished. You would need to review your incoming JSON, figure out the index of the ID column in the response, then apply that key attribute to that column index in the column model configuration. In our example the ID column is still first, lining up correctly, but in more complex column models and queries this can be different. Here's how you add that to the column model configuration.

jqGridDemo.js - Column Model Configuration

view plain print about
1colModel: [
2    {name: 'ID', hidden: true, key: true},
3    ...
4],

The importance in this can be viewed in the output. Here's a sample of the before and after difference in what jqGrid generates:

Grid Row Output - Before Key Definition

view plain print about
1<tr id="1" class="ui-widget-content jqgrow ui-row-ltr" role="row" tabindex="-1">

Grid Row Output - After Key Definition

view plain print about
1<tr id="FF318BAB-3048-71C2-17E1634637074ECF" class="ui-widget-content jqgrow ui-row-ltr" role="row" tabindex="-1">

Why is this important? When you go to the next page of records, if you hadn't applied the key then the first record displayed would also show an id of 1. And this now brings us to the bit that we're going to address with jqGrid. If you select a few rows, pull the selarrrow, then page and select some more and check again, you will see that jqGrid isn't tracking id's across paging requests. This means that, if you go back to page 1, your original selections are no longer checked. For some this may be ok, but many users will expect different behavior. This is part of a developer's life, is anticipating user behavior, and adjusting to meet good usability guidelines.

Event Handlers

So, what is expected behavior? If a user selects a record, then goes to another page, and then returns to the original page, then the user will expect their selections to have been maintained across paging requests. This becomes especially important to users working with very large amounts of data. So, how do we handle this? Well, we setup an Event Handler for our selections, and programmatically control it. First, let's create another global variable to hold selected id's.

view plain print about
1var gridCols = {set:false},
2    gridMultiSelect = 1,
3    selArr = [];

This is just an array, just like jqGrid uses internally. Next thing we'll do is setup some Event Handlers. Any time a selection (or deselection) is made, then we need to control the contents of our new selArr array. First we'll setup a method to apply to our onSelectRow grid Event Handler.

jqGridDemo.js - rowSelectionHandler

view plain print about
1var rowSelectionHandler = function (id, status) {
2    // process code here
3};

jqGridDemo.js - Grid Configuration Event Handler

view plain print about
1grid.jqGrid({
2    ...
3    onSelectRow: rowSelectionHandler,
4    ...
5});

A review of jqGrid's Events documentation shows that the onSelectRow attribute will apply an event handler, and passes two arguments: id - the record id of the row being selected, and status - a boolean value noting selection (true) or deselection (false). jqGrid's onSelectAll attribute is similar, passing idArr - an array of selected row id's, and status - if all were selected or deselected. We'll setup a handler for that as well.

jqGridDemo.js - selectAllHandler

view plain print about
1var selectAllHandler = function (id, status) {
2    // process code here
3};

jqGridDemo.js - Grid Configuration Event Handler

view plain print about
1grid.jqGrid({
2    ...
3    onSelectAll: selectAllHandler,
4    ...
5});

Now, it may be that we'll want to use these two methods for something other than keeping track of our new array. Ultimately, the work for handling our new array is the same for either, we just have to code in handling the difference between a single id being passed, or an array of id's being passed. We'll setup a separate method for the array manipulation, and call it from our new handler methods.

jqGridDemo.js - Handlers and selectionManager

view plain print about
1var rowSelectionHandler = function (id, status) {
2    selectionManager(id, status);
3 // anything else
4};
5
6var selectAllHandler = function (idArr, status) {
7    selectionManager(idArr, status);
8 // anything else
9};
10
11var selectionManager = function (id, status) {
12    // was it checked (true) or unchecked (false)
13    if(status){
14        // if it's just one id (not array)
15        if(!$.isArray(id)){
16            // if it's not already in the array, then add it
17            if($.inArray(id,selArr) < 0){selArr.push(id)}
18        } else {
19            // which id's aren't already in the 'selected' array
20            var tmp = $.grep(id,function(item,ind){
21                return $.inArray(item,selArr) < 0;
22            });
23            // add only those unique id's to the 'selected' array
24            $.merge(selArr,tmp);
25        }
26    } else {
27        // if it'
s just one id (not array)
28        if(!$.isArray(id)){
29            // remove that one id
30            selArr.splice($.inArray(id,selArr),1);
31        } else {
32            // give me an array without the 'id's passed
33            // (resetting the 'selected' array)
34            selArr = $.grep(selArr,function(item,ind){
35                return $.inArray(item,id) >
-1;
36            },true);
37        }
38    }
39    $('#t_gridTest button#exportButton').button((selArr.length >
0)?'enable':'disable');
40};

I've tried to comment the code above to explain our new selectionManager method. The only line I haven't explained is the last, which either enables or disables the Export button in the toolbar, depending on if any items are selected or not. Now, if you made selections, paged through and made other, deselected items, even selected 'all', you could look at the selArr variable and see that we are now tracking all selected records across paging requests. The only thing missing is that these records aren't selected (visually) when you return to a page. We can rectify that by applying a handler to our gridComplete attribute.

jqGridDemo.js - - Grid Configuration Event Handler

view plain print about
1grid.jqGrid({
2    ...
3    gridComplete: gridLoadInit,
4    ...
5});

jqGridDemo.js - gridLoadInit

view plain print about
1var gridLoadInit = function () {
2    // if the 'selected' array has length
3    // then loop current records, and 'check'
4    // those that should be selected
5    if(selArr.length >
0){
6        var tmp = grid.jqGrid('getDataIDs');
7        $.each(selArr, function(ind, val){
8            var pos = $.inArray(val, tmp);
9            if(pos > -1){
10                grid.jqGrid('setSelection',val);
11            }
12        });
13    }
14};

jqGrid's gridComplete attribute allows us to define an Event Handler that fires once data has loaded into the grid (this is not to be confused with loadComplete, which occurs after every server request.) What we're saying here is, after the data is rendered in the grid we will loop the selArr array and 'check' any id's that match any records displayed in our grid. This gridLoadInit method, that we've created, will now run anytime the grid's data is reloaded (initial load, paging requests, sorting, etc).

And so we've created a solution to rectify a small oversight within jqGrid. In the process we covered the importance, and the process, behind properly identifying a key column, in setting proper row id's, how to add a checkbox column through the multiselect attribute, how to apply event handlers to our grid, as well as adding a toolbar and filling it with controls. Next post we'll get to binding event handlers to our Action column icons, and search for some other nuggets to impart. Until then, I hope this all helps someone, and sample code is located in the Download link at the bottom of the post.

2011 In Review, and the View for 2012

My, how time flies when you're having fun! It seems like only yesterday that I was welcoming in 2011, and now we're here a year later. So many things have happened in the last year, and rereading that post I see that I missed some things I should've done, but let's take a look in retrospect.

I wrote 27 blog posts in 2011. This is nothing, compared to guys like Ray Camden or Ben Nadel, but for me it was quite a bit, especially when you consider that between March and August I released only one post. Very early in the year, I began a series on creatingmany sites with one codebase. In the process, the series has evolved to contain a fairly detailed primer in ColdFusion application architecture (because of it's importance to this process), has currently spanned 8 separate posts, and was even referenced by Sean Corfield in his great presentations on the same topic. 2012 will see the completion of that CF app discussion, and gradually move it back to the MSOC topic itself, as there is still a ton to talk about there, and a lot of interest in the topic. I also began a series on the jqGrid JQuery plugin. jqGrid is another Data Grid visualization tool (I have now written about three, including Ext JS and DataTables), and is a clear choice for those who must use JQuery. (To be fair, JQueryUI is working on a grid component, but they are still behind the curve, and way behind Sencha.) Finally, one common thread seen in the majority of my posts, is how much I've embraced cfscript. I wrote a lot of things, on a variety of topics, but most of my code examples were pure scripted examples.

Now let's talk about some other departures from the norm for Cutter.

You did not see a lot of content around Ext JS. In fact, I stopped writing Ext JS books. This is not, in any way, a reflection on my feelings for Ext JS. I still believe that Sencha has built one of the best client-side libraries for web application development. In evaluating the overall ROI, I realized that I was writing more for the community than the money, and that my reach was greater through my blog, while giving me flexibility on when and what I deliver from a content standpoint. That said, I didn't have a single project this year that used Ext JS, so had very little time to experiment and write about it. This year, I'm going to expand on a personal project, and get back to some great Ext JS content for my readers.

You, also, did not see me speak at any conferences this past year. Nor at any user group meetings. This wasn't because I didn't want to, but because of some more personal reasons. I'm not going to go in depth here, other than to say that I've had some long standing health issues that required me to have some surgery done on my mouth. (Mark Drew is making a joke right now...) Aside from the fact that this has been very costly (chewing up any conference/travel budget), it also meant that my speech has been affected for a good part of the year. Thankfully this experience is (mostly) over now, and I hope to get back to presenting sometime this year. Any user group looking for a speaker this year, please contact me through the Contact link on this blog.

One group I am hoping to speak to this year is the Northeast Florida CFUG. I have to call Mike back, but he's looking to get things kicked off again, and I want to help it be successful. If you're in or around the Jacksonville area, make sure to keep an eye on the site for upcoming events.

One other thing I'm looking to do is to migrate all of my projects into GitHub. I've been using Git at work, and I am loving it, and I think combining GitHub with RIAForge is a great way to promote the terrific technologies we work with every day. I will make the time, I promise.

This comes to the final discussion of this post, Adobe. I again had the pleasure of being an Adobe Community Professional this past year. Due to my health issues, I didn't get to do everything I would've wanted to this year, but I've tried to be a good supporter. There are some fabulous things coming in ColdFusion Zeus and, by extension, to ColdFusion Builder as well. There has been a lot of hub-bub over Adobe's communications flubs regarding Flash, mobile, and Flex. I've avoided much of the discussion, other than to say "be patient and watch". Flash isn't going away, and neither is Flex. HTML 5 is a beautiful thing, if you aren't developing desktop browser applications (i.e. You're only writing for mobile/tablet development). There, that is my whole contribution to that discussion. Give it a rest.

2012 will be a fantastic year. Set yourself some clear, definable goals. Break them down, step by step, and write the steps down on paper. Each successive step, print out in large letters and place it somewhere where you will see it each and every day. Set yourself up to succeed, and you will. Have a great year, everyone, and I can't wait to hear what you have planned for 2012.

Intro to jqGrid Part 3: Columns

OK, in our last two posts we built a basic grid and populated it with data. As you can see, so far it's a very basic grid.

Nothing much to it, really. Let's start adding a few important pieces. jqGrid includes a large set of Column Model Options, but there really aren't a ton that you'll need. Here we'll run through some basics.

First, the id field really isn't something you typically need to show anyone. So, just hide it.

jqGridDemo.js - Column Model - Hide

view plain print about
1colModel: [
2    {name: 'ID', hidden: true},
3    ...
4],

Oh yeah, and the views column is a count of the number of page views. As a number, it should probably be right justified.

jqGridDemo.js - Column Model - Align

view plain print about
1colModel: [
2    ...
3    {name: 'VIEWS', align: 'right'}
4],

Great! But that column is way too wide! Without any additional info, jqGrid will attempt to size the columns according to their data, and currently it's just making three even columns. Let's size it down.

jqGridDemo.js - Column Model - Width

view plain print about
1colModel: [
2    ...,
3    {name: 'VIEWS', align: 'right', width: 60, fixed: true}
4],

Alright! We've set a 'fixed' width, so that any resizing of the grid (even automatic resizing) will maintain the set column width. We set it to give full width of the column title, as well as some room for the sort markers when the column is being sorted.

Now let's talk about three options that can be somewhat confusing: index, label and name. Up until now we've used the name option, which has mirrored the column name being returned. However, we might want our column header to be different than the actual column name. For this, we use the label option.

jqGridDemo.js - Column Model - Label

view plain print about
1colModel: [
2    ...,
3    {name: 'POSTED', label: 'Release Date'}
4],

This changed the label used in the column header, while maintaining a reference used when sorting the grid by the posted field. This is good, until you do something like this:

jqGridDemo.js - Column Model - Remap

view plain print about
1grid.jqGrid('setGridParam',{remapColumns:[
2    gridCols['ID'] + gridMultiSelect,
3    gridCols['ID'] + gridMultiSelect,
4    gridCols['TITLE'] + gridMultiSelect,
5    gridCols['POSTED'] + gridMultiSelect,
6    gridCols['VIEWS'] + gridMultiSelect
7]});

jqGridDemo.js - Column Model - Index

view plain print about
1colModel: [
2    {name: 'ID', hidden: true},
3    {name: 'Action', index: 'ID', label: 'Action', width: 80, fixed: true, sortable: false, align: 'center'},
4    {name: 'Title'},
5    {name: 'Posted', label: 'Release Date'},
6    {name: 'Views', align: 'right', width: 60, fixed: true}
7],

"Cutter, What are you doin' ta me!?!" Yeah, now it's confusing. I've added a column. A column that also references the ID field in the return dataset. In this instance the index really isn't truly necessary, but I'll try to explain it for you anyway. Up until now, jqGrid has used the name option as the value that is passed back to the server on a sort request. Here's the thing though: each column has to have a unique reference. That's what the name option is for; being a unique column reference within jqGrid. So, if you have two columns whose underlying data is the same (as it shows you in our new Remap config), then you need a unique reference for jqGrid (the name), and the index field reference that jqGrid will send back to the server on sort requests (again, with the sortable: false I've thrown in here, it's really moot for us). So, to recap:

  • name - A unique column reference used by jqGrid
  • index - A data field reference used in sort requests. If not present then the name is used.
  • label - If present it will override the name option, for what to display in the column header.

You probably noticed that I added a little something to our column remap code.

view plain print about
1gridCols['ID'] + gridMultiSelect,

This goes along with a new variable I added to our global variable declarations at the very top of our script.

view plain print about
1var gridCols = {set:false},
2    gridMultiSelect = 0;

I'll probably not use that on this round, but it will become important, so I'll leave it for now.

Column Formatting

Now that we've talked about some of the more important column options, let's get into column formatting. Now that we've added some configuration you'll notice a new Action column. Right now, if you ran your template, you'd see a truncated ID value in the cells. We'll need that ID in our output, but the Action column we're building will be used to display action icons (edit, delete, etc). jqGrid has functions for doing this, if you're using it's edit packages, but my app has custom editors for a lot of this data, so we'll apply a custom column formatter to show these action icons.

jqGrid provides predefined formatters for many things, but you can also create your own custom formatters to create your own cell templates. A custom formatter is just a function, applied through the column model, that returns the string to be displayed in the cell. Your function will take three arguments, cellvalue, options, and rowObject. The cellvalue is the value of the data that jqGrid is trying to apply to the cell (in our case, a record's ID). The options is an object containing the rowId and the colModel of the record being applied. The rowObject is the data for the entire row of the record being applied.

jqGrid provides the ability to apply these functions as extensions of it's built in formatter package. Let's write a basic actionFormatter function that returns just the first two characters of the ID field, to get started.

jqGridDemo.js - actionFormatter - figure 1

view plain print about
1$.extend($.fn.fmatter, {
2    actionFormatter: function(cellvalue, options, rowObject) {
3        return cellvalue.substr(0,2);
4    }
5});

jqGridDemo.js - Column Model - Custom Formatter

view plain print about
1colModel: [
2    ...
3    {name: 'Action', index: 'ID', label: 'Action', width: 80, fixed: true, sortable: false, align: 'center', formatter: 'actionFormatter'},
4    ...
5],

That was easy! You see now how we get to value being applied to the cell. Now let's really change it up, by applying the custom output we discussed before. First, we need the style references to the icons we're going to use.

jqGridDemo.css - icons

view plain print about
1/* Basic layout of all trigger icons */
2.icon-trigger { margin: 2px; vertical-align: middle; display: inline-block; width: 16px; height: 16px; }
3.action-trigger { cursor: pointer; }
4.disabled-trigger {opacity:0.4;filter:alpha(opacity=40)!important;}
5
6/* delete icon image for trigger */
7.delete { background: url('/resources/images/icons/delete.png') no-repeat scroll 0px 0px transparent !important; }
8
9/* pencil icon image for trigger */
10.pencil { background: url('/resources/images/icons/pencil.png') no-repeat scroll 0px 0px transparent !important; }

For our demo, I'm using the highly useful FamFamFam Silk icon library. Here I've defined some classes for the display of icon 'triggers', or icons that are used as buttons for actions. Next, we'll adjust our actionFormatter to apply the proper output.

jqGridDemo.js - actionFormatter - figure 2

view plain print about
1$.extend($.fn.fmatter, {
2    actionFormatter: function(cellvalue, options, rowObject) {
3        var retVal = "<span class=\'icon-trigger action-trigger pencil\' rel=\'" + cellvalue + "\' \/>";
4        retVal += "<span class=\'icon-trigger action-trigger delete\' rel=\'" + cellvalue + "\' \/>";
5        return retVal;
6    }
7});

As you can see, now when you re-run your template you have a nice, formatted Action column, with action icons for 'edit' and 'delete'.

So, in this post we covered some of the more important Column Model display options, as well as creating a custom column formatter. In our next entry we'll tie some functions to our 'action icons', and talk about row selection options. You can find sample code attached in the Download link at the bottom of the page.

Intro to jqGrid Part 2: Getting the Data

As I mentioned in an Intro to jqGrid, sometimes you have to deal with remote data that isn't in the 'standard' JSON recordset format. I also like to reuse my server-side code, and prefer not to unnecessarily hack native data to meet a client-side need. For this reason, it is often necessary to write client-side methods that parse the server-side native format. Unfortunately, many JQuery plugins only handle the 'standard' JSON recordset format:

[More]

Intro to jqGrid

While there are better choices (ExtJS for instance) for component and architecture libraries, some time ago someone entrenched our current system in JQuery and JQueryUI. But, since JQueryUI is already so prevelent within the system, it would be very time consuming to replace it. JQueryUI isn't bad, by any means, just incomplete, from the standpoint of building "applications". "But, JQueryUI is the bomb! How can you say such things?" Well...

[More]