Displaying Alternative Coloured Images in JQ Grid

 

Whilst coding up a recent .NET MVC application built heavily using JQGrid I came across a requirement which to be honest I struggled with at first . In short I wanted to, on a column by column basis, colorise the icons that were to be displayed. Now JQGrid supports a icon colorset which seemingly cannot be changed easily so in the end I had to resort to changing the styles. Here is how I achieved this, warts and all….

Firstly of course JQGrid uses the standard set of JQuery Ui Icons to provide its user interface. I say ‘Icons’ but this is of course provided as one image which is broken up into sprites of 16 x 16 pixels, more of that later. So the first step is to download the set of colour icons that you require…. JQueryUI.com provides a standard set of these icons rolled in every colour you can dream so its in fact very easy. The hardest part is arriving at your chosen colours!

I arrived at the following soft representation of the Red, Amber and Green colours :-

  • Red Hex: FF99A3
  • Amber Hex: FFB380
  • Green Hex: 99FFB8

So using these hex values i was able to download my chosen colour schemes using the following url:-

http://download.jqueryui.com/themeroller/images/ui-icons_*HEXCOLOR*_256x240.png

In my instance i downloaded the following files:-

  • http://download.jqueryui.com/themeroller/images/ui-icons_FF99A3_256x240.png
  • http://download.jqueryui.com/themeroller/images/ui-icons_FFB380_256x240.png
  • http://download.jqueryui.com/themeroller/images/ui-icons_99FFB8_256x240.png

As you can see from the screen grab below the resultant images are in fact compound images containing many 16 x 16 sprites:

FF99A3

In my case I need to use the following icons Bullets and Ticks, as you can see if you examine the image the tick sprite is the fifth sprite across on the tenth line down whilst the bullet is the sixth character on the same line. Given that each character is 16 pixels wide and tall finding the location is relatively easy. The basic formula is (n-1) x16  expressed as a negative where n is the line number or character across.  So in the case of our tick as it is the fifth character across its horizontal location starts at -64 pixels, similarly its vertical location is -144 pixels (9 x 16 expressed as a negative)

We thus need to create some css classes to represent these icons so in my instance I created the following classes:-

.ui-green-tick{
width:16px;
height:16px;
background-image:url(../css/redmond/images/ui-icons_99FFB8_256x240.png)!important;
background-position:-64px -144px
}
.ui-red-tick{
width:16px;
height:16px;
background-image:url(../css/redmond/images/ui-icons_FF99A3_256x240.png)!important;
background-position:-64px -144px
}
.ui-amber-tick{
width:16px;
height:16px;
background-image:url(../css/redmond/images/ui-icons_FFB380_256x240.png)!important;
background-position:-64px -144px
}

.ui-green-bullet{
width:16px;
height:16px;
background-image:url(../css/redmond/images/ui-icons_99FFB8_256x240.png)!important;
background-position:-80px -144px
}
.ui-red-bullet{
width:16px;
height:16px;
background-image:url(../css/redmond/images/ui-icons_FF99A3_256x240.png)!important;
background-position:-80px -144px
}
.ui-amber-bullet{
width:16px;
height:16px;
background-image:url(../css/redmond/images/ui-icons_FFB380_256x240.png)!important;
background-position:-80px -144px
}

Note that each class points to the relevant colour image using the background-image:url property, in order to ensure that our image takes precendence over other images referred to in the JQGrid style sheets I habd to also use the !Important declaration, The sprite location is specified using the background-position: properties using the algorithm discussed above. As you can see we also specify the size of our images. in this instance 16 x 16 pixels.

OK, so believe it or not thats the worst part over with, all that is left now is for you to determine on a row by row and column by column basis which icons are to be displayed and change the relevant classes using javascript I defined the following javascript helper functions, some code has been removed for brevity so they may not be compilable (apologies in advance).

function OnLoadPrimeGridExclusive(grid, actionColumn, theTitle, dataColumn) {

    var iCol = getColumnIndexByName(grid, actionColumn);
    grid.children(“tbody”)
            .children(“tr.jqgrow”)
            .children(“td:nth-child(” + (iCol + 1) + “)”)
            .each(function () {
                $(“<div>”,
                    {
                        title: theTitle,
                        mouseover: function () {
                            $(this).addClass(‘ui-state-hover’);
                        },
                        mouseout: function () {
                            $(this).removeClass(‘ui-state-hover’);
                        },
                        click: function (e) {

                            /* Get the Contexts that we are using here. We need to know the Row
                                and the span in order to accomplish this task……*/

                            var row = $(e.target).closest(“tr.jqgrow”);
                            var span = $(e.target).closest(“span.ui-icon”)

                            /* And now call the Toggle Routine that will toggle the selection */

                            ToggleSelectedSelection(row, span, grid, dataColumn, true);

                            grid.saveRow($(row).attr(“id”), {
                                aftersavefunc: function (id, response, options) {
                                    var someRetValue = response; // set someRetValue to any value
                                }
                            });
                        }
                    }
                  ).css({ “margin-left”: “5px”, float: “left” })
                   .addClass(“ui-pg-div ui-inline-custom”)
                   .append(‘<span id=””></span>’)
                   .appendTo($(this).children(“div”));

                var row = $(this).closest(“tr.jqgrow”)
                var span = $(this).find(“span.ui-icon”);
                ToggleSelectedSelection(row, span, grid, dataColumn, false);

            });
    }
}
function ToggleSelectedSelection(row, span, grid, fieldName, toggle) {

    /* Get the Row id for the current row */

    var rowID = $(row).attr(“id”);
    var unselected =  bulletClass(fieldName);
    var selectedClass = tickClass(fieldName);

     /* And get the current selected value */

    var selected = grid.jqGrid(‘getCell’, rowID, fieldName);
    var removeClass = null;
    var addClass = null;
    var selectionState = null;

    /* Now work out what we need to show */

    if (toggle) {
        removeClass = (selected == ‘false’ || selected == false) ? unselected : selectedClass;
        addClass = (selected == ‘false’ || selected == false) ? selectedClass : unselected;
        selectionState = (selected == ‘false’ || selected == false) ? “true” : “false”;
    } else {
        addClass = (selected == ‘false’ || selected == false) ? unselected : selectedClass;
        removeClass = (selected == ‘false’ || selected == false) ? selectedClass : unselected;
    }

    /* And do that thing! */

    $(span).removeClass(removeClass);
    if (addClass != “”) {
        $(span).addClass(addClass);
    }
    if (selectionState != null) {
        grid.editRow(rowID);
        grid.jqGrid(‘setCell’, rowID, fieldName, selectionState, “”);
        grid.saveRow(rowID, {
           aftersavefunc: function (id, response, options) {
              }

         }
        );
    }
}

function bulletClass(fieldName) {
    switch (fieldName) {
        case “Red”: {
            return “ui-red-bullet”;
        }
        case “Amber”: {
            return “ui-amber-bullet”;
        }
        case “Green”: {
            return “ui-green-bullet”;
        }
        default: {
            return “ui-icon-bullet”;
        }
    }
}

function tickClass(fieldName) {
    switch (fieldName) {
        case “Red”: {
            return “ui-red-tick”;
        }
        case “Amber”: {
            return “ui-amber-tick”;
        }
        case “Green”: {
            return “ui-green-tick”;
        }
        default: {
            return “ui-icon-check”;
        }
    }
}
function  getColumnIndexByName (grid, columnName) {
    var cm = grid.jqGrid(‘getGridParam’, ‘colModel’), i = 0, l = cm.length;
    for (; i < l; i += 1) {
        if (cm[i].name === columnName) {
            return i; // return the index
        }
    }
    return -1;
}

And in the loadComplete event of the grid the following javascript starts the whole process….. If you are only colourising one column you need only call this routine once

OnLoadPrimeGridExclusive(grid, ‘RedAction’, ‘De/Select Red Rating’, ‘Red’, true);
OnLoadPrimeGridExclusive(grid, ‘AmberAction’, ‘De/Select Amber Rating’, ‘Amber’,true);
OnLoadPrimeGridExclusive(grid, ‘GreenAction’, ‘De/Select Green Rating’, ‘Green’, true);

A few notes that need to be made here, for each display column where the actual image is displayed ticked or not in this instance the columns RedAction/GreenAction/AmberAction there is also a hidden checkbox type data column which physically stores the boolean value indicating whether or not the grid is ticked or not (entitled Red/Green/Amber). This column is manipulated whenever the user clicks on an image to toggle the selection and the icon is set according to the underlying value of that column.

My time with JQGrid on this particular project has not been a happy one, I started off using the .NET MVC implementation but have overtime reverted to using the plain old javascript version as it offers a great deal more control and configurability. I think we may have turned a corner now and so thought I’d like to share some of that positivity with the community.

I hope this helps.

Leave a Reply

Your email address will not be published. Required fields are marked *