Displaying the Data






Displaying the Data

Displaying data in the grid requires the ability to create rows and columns. These rows and columns need to handle rendering data into a structured display. This display will represent the data grid and typically handle interactive functionality, which in our case will invoke the actions that we are setting in the XML.

Creating a DataRow Object

The DataRow object separates data of matching groups into rows, which will eventually be subdivided into columns. Since the object is a prototype, in order to create and instantiate the object, we need to build a constructor function for the object. As you can see in the constructor function in Listing 13.8, we are passing the five parameters that were used in the DataRow objects that we instantiated in the DataGrid object. These parameters are id, items array, action, parity, and icon.

Listing 13.8. Constructing the DataRow (DataRow.js)

function DataRow(id, items, action, parity, icon)
{
    this.id = id;
    this.icon = icon;
    this.items = this.getAllItems(items);
    this.action = action;
    this.parity = parity;
}

The parameters that we accept in the DataRow constructor are set to local properties within the object. All of these parameters are directly translated into local properties except for the items array. This parameter calls another method in the object called getAllItems, which parses the node values from the items and returns an array of DataColumn objects, which is then set to the local items array. We will create the getAllItems method in just a bit.

The display method is what we called in the DataGrid object to return the HTML for each of the rows. We then took this data and appended it to the datagrid div element. Take a look at Listing 13.9 to see how we create the HTML elements for the rows in the display method.

Listing 13.9. Displaying a DataRow (DataRow.js)

DataRow.prototype.display = function()
{
    var row = Utilities.createElement("div", {
      id: 'row_'+ this.id,
      className: 'row_'+this.parity,
      onclick: this.getAction(this.action),
      onmouseover: this.rollOver('row_'+ this.id),
      onmouseout: this.rollOut('row_'+ this.id)
      });

    for(var i=0; i<this.items.length; i++)
    {
        Utilities.appendChild(row, this.items[i]);
    }
    return row;
}

The display method is the control center for the object. It not only contains all the code to render the rows, but it also holds all the event handlers. This method is used as the access point from other objects and combines all of the other methods in the object to return a complete row element with interactive event handlers to the front end or the GUI. After the element is constructed, we need to iterate the items array, which includes DataColumn elements, to the current row. The row element this method creates has a unique id, a class name, and onclick, onmouseover, and onmouseout events. The unique id is used to uniquely identify the row, which can be used to provide us with a way to target the object by name. The class name is where the parity comes into play. The parity provides us with a way to concatenate two different class names: row_even and row_odd. In our sample, these classes differ by providing background colors that alternate from even to odd rows, leaving us with a way to distinguish one row from the other. Of course, these classes could be modified to display the rows in other unique ways, but I'll leave that part up to you. The events that are created give our row interactivity and enhance the user experience of the component. The first event is the onclick event that we set to the getAction method and pass the action property as a parameter. This method takes the action and returns a function to the event. Therefore, when the row is clicked, a function is invoked. This function then evaluates the action and fires it after it validates. Take a look at Listing 13.10 to see this method in action.

Listing 13.10. Creating an Action from the Parsed XML (DataRow.js)

DataRow.prototype.getAction = function(action)
{
    return function()
    {
        eval(action)
    }
}

The next event handler that we are adding in the row element is the onmouseover. This event is set to the local rollover method within the object. In the sample, we are using the rollover method to handle the styles for the rows. In this case, we are simply changing the color and setting the cursor to the hand pointer to distinguish the row as a clickable item (see Listing 13.11).

Listing 13.11. Rolling Over a Row (DataRow.js)

DataRow.prototype.rollOver = function(id)
{
    return function()
    {
        Utilities.getElement(id).style.backgroundColor = '#999';
        Utilities.getElement(id).style.cursor = 'pointer';
    }
}

The last event handler is the onmouseout event, which calls a method called rollout. This method is very similar to the rollover method because it also changes the color of the background, but in a different way. When a user rolls out of the row, we want the row color to return to its previous state. Therefore, we need to reset the color in this method, but it gets a little trickier. We have the alternating colors from one row to the next, so in order to handle this, we need to check the parity of the object calling it and base the background color on the parity.

There is another item of interest in this method, which we have covered in previous chapters: the scope of the this keyword. When the JavaScript object is created, the scope works fine, but during runtime the events associated with an element will not know the scope of the this keyword or even what this refers to. Therefore, we need to set a variable called _this to this, which is equal to the object scope, when we create the method in the object. This allows the variable to scope properly when we fire an event during runtime and ultimately allows us to read specific properties based on the current object. Listing 13.12 shows the rollout method in its entirety.

Listing 13.12. Rolling Out of a Row (DataRow.js)

DataRow.prototype.rollOut = function(id)
{
    var _this = this;
    return function()
    {
        if(_this.parity == "even")
        {
            Utilities.getElement(id).style.backgroundColor = '#eaeaea';
        }
        else
        {
            Utilities.getElement(id).style.backgroundColor = '#fff';
        }
        Utilities.getElement(id).style.cursor = 'none';
    }
}

The last method in the DataRow object is one that I have previously mentioned. This getAllItems method takes an array of nodes and creates DataColumn objects, which it appends to an array and returns to the DataRows items array (see Listing 13.13).

Listing 13.13. DataRow.js

DataRow.prototype.getAllItems = function(items)
{
    var columns = new Array();
    for(var i=0; i<items.length; i++)
    {
        for(var j=0; j<items[i].childNodes.length; j++)
        {
            var copy = StringUtil.trim(items[i].childNodes[j].nodeValue, 50);
            columns.push(new  DataColumn(j, copy).display());
        }
    }
    return columns;
}

The first thing we do is create a new column array, and then we begin to iterate through the items array that was passed as a parameter. While iterating through this loop, we will need to nest another loop, which iterates the childNodes in the items. Now that we are iterating at the value depth for the items, we can target the nodeValue for each item. We then take this value and pass it to a trim method in an object called StringUtil, which takes a string and a number as parameters. This method returns a trimmed version of the string at the number of characters specified as the second parameter. After we retrieve this trimmed version of the copy, we use it as a parameter in the DataColumn. We then push an HTML version of the DataColumn to the columns array by invoking the display method for the object. After we have completed iterating and constructing the columns array, we return it.

Now that we know how to create a DataGrid object and construct DataRows to be displayed within it, we will complete our grid by creating the DataColumn object.

Creating a DataColumn Object

The DataColumn object handles separating groups of corresponding data into columns. The DataColumn object takes two parameters, id and copy, which both get scoped to local properties in the constructor function. This object is very small because it simply constructs itself and displays its data. The display method handles the creation of column divs. Each column div contains a unique id, a class name of column and innerHTML, which is equal to the copy parameter that was passed to it by the DataRow object. After the column is constructed, it is returned to the object that calls it. See Listing 13.14 for an example.

Listing 13.14. DataColumn.js

function DataColumn(id, copy)
{
    this.id = id;
    this.copy = copy;
}

DataColumn.prototype.display = function()
{
    var column = Utilities.createElement("div", {
      id: 'column'+ this.id,
      className: 'column',
      innerHTML: this.copy
      });

    return column;
}

Adding Design to the Component

The CSS for the DataGrid handles the design for the each component's GUI elements. The first item we will set a class for is the datagrid element (see Listing 13.15). This class will simply define the width of the grid component, but we could easily add a background color or a border, for example, to make it more appealing.

Listing 13.15. Styling the datagrid Element (datagrid.css)

#datagrid
{
    width: 600px;
}

The next two classes are related to the parity method that we used in the DataRow object. Depending on whether the row is even or odd, we assign one of these classes. Each class is composed of a float, which aligns the rows to the left. It also contains a width and a background color (see Listing 13.16).

Listing 13.16. Styling Alternating Rows (datagrid.css)

.row_even
{
    float: left;
    width: 600px;
    background-color: #eaeaea;
}

.row_odd
{
    float: left;
    width: 600px;
    background-color: #fff;
}

The last three classes represent the titles and the columns of the grid. The titlebar and the title classes handle the design for the category titles in the grid, setting the background properties for the bar and the font rendering from the title itself. The last class is the column class, which floats the columns to the left and aligns each one in its respective row. This class also sets the width and the padding around the content within each of the columns. See Listing 13.17 for an example.

Listing 13.17. Styling Titles and Columns (datagrid.css)

.titlebar
{
    float: left;
    width: 140px;
    padding: 5px 50px 5px 10px;
    background-color: #666;
}

.title
{
    font-weight: bold;
    color: #fff;
}

.column
{
    float: left;
    width: 140px;
    padding: 5px 50px 5px 10px;
}

The beautiful part of using CSS and div elements for the component is that these classes can be modified to render the data grid in a million different ways. This means that you can reuse this component in any situation and make it fit within any design necessary. The objects can also be easily modified to include additional functionality, such as resizable rows and columns or an action column for adding, editing, and deleting information from the grid. These are only a few ideasI am sure you already have many of your own.



 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows