dhtmlxGrid. Step-by-step guide

We probably developed the best grid you've ever seen. But to feel this you need to know how powerfull and simple it is. This thought forced me to describe easy way of getting dhtmlxGrid to work with you. Lets start from basics and go to more complex functionlity (which is still quite simple with dhtmlxGrid). At the end will have grid with 100.000 records in it with filtering and sorting, which will work realy fast.

Step 1 - Include script and css files into the page

First of all let's place files we need for grid: dhtmlxcommon.js - file includes common objects shared by all dhtmlx components like AJAX request processors, error handlers, various tools and parsers used by components, dhtmlxgrid.js - main grid engine and API, dhtmlxgridcell.js - grid cells engine and default cells, dhtmlxgrid_srnd.js - this file contains code for Smart Rendering - technology which allows loading big datasets and still get them fast in grid

And styles: dhtmlxgrid.css - main grid styles file, dhtmlxgrid_skins.css - it contains various predefine skins related styles so you do not need to include it if you are not going to use predefined skins. I'll include it as I'm going to apply "light" skin to the grid.

<link rel="STYLESHEET" type="text/css" href="codebase/dhtmlxgrid.css"> <link rel="STYLESHEET" type="text/css" href="codebase/dhtmlxgrid_skins.css"> <script src="codebase/dhtmlxcommon.js"></script> <script src="codebase/dhtmlxgrid.js"></script> <script src="codebase/dhtmlxgridcell.js"></script>

Step 2 - Place grid on the page

There are two ways to place grid on the page, but as the main goal of this article is to show the simpicity of dhtmlx components usage, I'll go the most common way. So I need to place DIV on my page and set ID attribute to some unique value. Also I'll specify grid width and height right in style attribute of the DIV.

<div id="mygrid_container" style="width:600px;height:150px;"></div>

Now I proceed to the main fase of the process - defining grid parameters. So in script block I write the following:

var mygrid; function doInitGrid(){ }

doInitGrid function will contain grid initialization code (not so much code I would say):

mygrid = new dhtmlXGridObject('mygrid_container'); mygrid.setImagePath("codebase/imgs/"); mygrid.setHeader("Model,Qty,Price"); mygrid.setInitWidths("*,150,150"); mygrid.setColAlign("left,right,right") mygrid.setSkin("light") mygrid.init();

Now we need to run this function. It is important to run it after DIV element we would use for grid iniialization was loaded. So I could place this function call in script block right after mentioned DIV, but I prefer to use onload event of body element for this. So my body tag will look like this:

<body onload="doInitGrid();">

If you run the page now it should look like this:

Step 3 - Populate Grid with Data

As you probably already know dhtmlxGrid can load data from XML, CSV (text file where values separated by some character like comma or any other). It also can be populated with javascript methods. In this article I'll describe loading from XML. Btw, loading data from XML doesn't mean that you can't load data from database. You'll see this later in the article.

XML structure understandable for dhtmlxGrid. To populate grid from XML you need data be structured in the way grid can understand. This is easy as the structure is intuitivly clear. Generally it consists of rows with cells inside. Each row should have unique identifier (This is important as grid should be able to distinguish one row from another). Cells values are inside cell tags. For our sample to work we need each row to have 3 cells inside (as soon as we set 3 columns in grid)

<?xml version="1.0" encoding="UTF-8"?> <rows> <row id="a"> <cell>Model 1</cell> <cell>100</cell> <cell>399</cell> </row> <row id="b"> <cell>Model 2</cell> <cell>50</cell> <cell>649</cell> </row> <row id="c"> <cell>MOdel 3</cell> <cell>70</cell> <cell>499</cell> </row> </rows>

Let's save this xml into file with the name "step3.xml" and place this file into same foder wi have index.html file where we implement the grid. The only one command you need to add to your doInitGrid function is mygrid.loadXML("step3.xml");. Put it after mygrid.init(); mygrid.loadXML("step3.xml");

If you run the page now it should look like this:

Grid still looks rather simple and has just few rows of data. In real life people use grids to show much more data - hundreds, thousands or sometimes millions of rows. This is possible with dhtmlxGrid. But for now three rows is enough.

Step 4 - Add client side sorting

To enable sorting of rows on client side ("client side" means that grid will do this in your browser without using any help from server) you need to define sorting type for each column in grid using mygrid.setColSorting(sortTypesStr); method, where sortTypesStr is list of types. There are four types available plus "na" - which means sorting not available for the column:

For example we are going to sort first column as string (str), second as number (int) and set no sorting for third. Then we need to add the following line of code before mygrid.init();

mygrid.setColSorting("str,int,int");

Now you can click on column header and sort rows in grid acording to the sorting types you've just specified. To find out about "custom sorting" you can here

If you run the page now and click on last column header grid should look like this:

Step 5 - Implementing Cell Editors for Formatting and Editing (cell types)

Cell Editiors (or eXcells - Extended Cells, Cell or Columns types) are used in grid to define value formating and way of editing. There are some predefined eXcells, delivered with the package (complete list is avalable here). Also there are some eXcells created by other developers. You also can create eXcells which will suite exactly your needs.

Setting cells types is easy - it can be done using one line of code. First of all, all eXcells have their own codes. These codes should be used while setting types. For example simple editor has code "ed", editor with popup multiline editing area - "txt", readonly cell - "ro", checkbox - "ch", price formatted cell - "price". In Standard Edition of gridthere is a possibility to set types on columns. In Professional you can set type as on column, as on each cell.

Let's add types to our grid. By default all columns has "ro" type. Some types can be assigned to any values, but some, like "price" for example should be assigned to cells with proper - numeric - values. Otherwise value will be omitted or incorrectly parsed. Taking this into acount, let's set first column editable with simple editor ("ed"), assign simple editor ("ed") on second one too and price formating with editing capabilities ("price") on last column. Line of code you need to add before mygrid.init() is the following:

mygrid.setColTypes("ed,ed,price");

Now you can enter editors double clicking on editable cell, or pressing F2. If you use tab key to navigate from one cell to another, then editor will be opened automatically for the cell which is in focus.

If you run the page now and double click on cell in third column it should look like this:

Step 6 - Add/Remove rows in grid

Here I would say some words about adding rows into grid and removing rows with the help of Script API (set of methods which help you manage grid through javascript). First of all we'll need to add two buttons to the page: Add Row, Remove Row. Do this by adding the following html code to the body of your page right after grid:

<br> <button onclick="addRow()">Add Row</button> &nbsp; <button onclick="removeRow()">Remove Row</button>

Most important things there are two function calls, which occure when you click first or second button: addRow() and removeRow() respectively. Let's add these function to script block, where you already have doInitGrid() function. The code you need to add is the following:

function addRow(){ var newId = (new Date()).valueOf() mygrid.addRow(newId,"",mygrid.getRowsNum()) mygrid.selectRow(mygrid.getRowIndex(newId),false,false,true); } function removeRow(){ var selId = mygrid.getSelectedId() mygrid.deleteRow(selId); }

Some comments about addRow() function code (line by line):

  • Creates unique value (number of miliseconds since 1970) to use as row identifier.
  • Adds row with new Id, empty values and put it after the last row in grid
  • Selects newly created row (by index), no calling for On-Select event handler, no preserving previously selected rows, with setting focus on selected row (will scroll to it if vertical scroller exists)
  • Some comments about removeRow() function code (line by line):

  • Gets Id of selected row
  • Deletes row with specified Id
  • Step 6 - How to Save Data on Server side

    O'key, we loaded data from server side and editted it. Now we need to send data back to server to update datasource. There are two ways for this:

  • use dhtmlxDataProcessor, which is ready to use client side solution for gathering and sending data to server as well as for processing server response
  • use dhtmlxGrid API to gather necessary data from grid, send it to server and process server response
  • Although dhtmlxDataProcessor is an easy way, I will go second way to show some API usage with dhtmlxGrid. So, first of all let's define what we need:

  • Catch the moment when cell value was updated
  • Mark row of grid as updated, but not saved (so, user can see the status of data)
  • Get row identifier (to know what row in datasource to update) and new cell value and send it to server for update
  • Update server side datasource
  • Get and process response from server (if update was successfull)
  • Return row marked as updated to normal state
  • Let's start. First point can be achieved with event handler for event "onEditCell". It occurs at the moment user opens, edits and closes editor in cell. Function which will be set as event handler will get 3 incomming values: stage (0-before cell editor was opened, 1 - cell editor was opened, 2 - cell editor was closed), row ID, cell index. If stage is 2, then it will get two additional values: new cell value, old cell value. I think this is enough to get all information we need. Here is the code for setting event handler (put it in doInitGrid function)

    mygrid.attachEvent("onEditCell",doOnEditCell);

    Before you load the page you need to define doOnEditCell function itself. Here is the code for it. Put it somewhere within script block:

    function doOnEditCell(stage,rId,cInd,nValue,oValue){ if(stage==2 && nValue!=oValue){ mygrid.setRowTextBold(rId) } }

    In common words: If stage is 2 (editor was closed) and new value not equel to old value, then make row text bold. If you put this code on the page, load page and edit any cell in grid chnaging its value and close editor (press Enter), you'll see something like this:

    Now user knows what row data was update (but wasn't saved yet). And we need to get new value of the cell and row identifier to send data to server side for update. Let's create simple functiuon which gets necessary value as incomming arguments and sends GET request to server. Also, as soon as we use AJAX for this requst, we'll define function which will be called when response from server comes

    function sendDataToServer(rId,cInd,value){ dataSender = new dtmlXMLLoaderObject(doAfterUpdate,window); dataSender.loadXML("saveData.php?rowId="+rId+"&cellindex="+cInd+"&value="+value); } function doAfterUpdate(){ alert("Update finished"); }

    Put this code on the page somewhere within script block. And also add one line of code to doOnEditCell function to call sendDataToServer function with necessary values. Place it after mygrid.setRowTextBold(rId). All values will be take from incomming values came to doOnEditCell function. Complete code of doOnEditCell function will be the following:

    function doOnEditCell(stage,rId,cInd,nValue,oValue){ if(stage==2 && nValue!=oValue){ mygrid.setRowTextBold(rId) sendDataToServer(rId,cInd,nValue); } }

    Now if you load the page, edit some cell and close editor - request with new value will be sent to server, response will come (at this stage it doesn't matter what is in response as we do not use it, we just need the fact that it comes) and alert appears. Like this:

    In reallity, nothing was updated, as we do not have real server side. What should server side do:

  • get values from request - rowId, cellindex and value (in PHP it will be this way: $_GET["rowId"],in ASP: ,)
  • Update values using SQL query
  • Response with xml, which should contain information about row identifier and status. Like this:
  • <status value="ok" rowid="[rowid]"> where [rowid] - identifier of updated row (in case of update it is the same as incomming row Id)

    If you set server side properly and it returns status is xml format as described below, then we need to add real code into doAfterUpdate instead of alert. Updated function will look like this:

    function doAfterUpdate(){ var docElement = dataSender.getXMLTopNode("status"); var statusVal = docElement.getAttribute("value"); var rowId = docElement.getAttribute("rowid"); if(statusVal=="ok"){ mygrid.setRowTextNormal(rowId); } }

    Here what it does:

  • Gets top element in XML which came from server (which is tag <status>)
  • Gets value of "value" attribute of tag <status>
  • Gets value of "rowid" attribute of tag <status>
  • If status is "ok", then make text in row with specified id as normal (it was set to bold when value in cell was updated)
  • Updating text to normal we tell user that update of cell value on server side was successful.

    Generally this was just a demonstration of what we can do in grid using API and it doesn't contain all necessary steps in process of saving data to server. In real life this process is more complex. Thus I would suggest using dhtmlxDataProcesor. It implements all necessary steps to process update/add/delete rows as well as drag-n-drop.

    To be continued...

    Step X - Using dhtmlxDataProcessor to establish proper client-server data processing.

    Step 7 - Loading really big datasets into grid with Smart Rendering

    Step 8 - Loading really big datasets from static dataset (no need for server programming)

    Step 9 - Sorting big datasets on server (PHP/MySQL)

    Step 10 - Filtering Data (PHP/MySQL)