My take on implementing searches with AJAX (Part 4)

by Ishai Hachlili 12. February 2008 13:40

In the previous posts in this series I collected the form values, executed the search and processed the search results columns on the server side.

Now it’s time to return the results to the client side and display the search results grid.

I’m going to use the WebFX columnlist for my grid. This is my favorite javascript grid control.
It allows column resizing and drag & drop reordering as well as client side sorting (which will be great for one page search results).
It doesn’t support any formatting or links in the grid, so I’ll have to make some upgrades to it.

If you look at the documentation for the WebFXColumnList, you can see it uses an array of the column names and an array of data rows where each row is an array of values (that should be in the same order as the column names).

JavaScript sample – showing a grid using WebFXColumnList

var aColumns = [
'Rank',
'Flavor',
'Color',
'Share'
];

var aData = [
['1','Vanilla','White','29%'],
['2','Chocolate','Brown','8.9%'],
['3','Butter pecan','Light brown','5.3%'],
['4','Strawberry','Pink','5.3%'],
['5','Neapolitan','Greenish brown','4.2%'],
['6','Chocolate chip','Brown','3.9%'],
['7','French vanilla','Yellowish white','3.8%'],
['8','Cookies and cream','Light brown','3.6%'],
['9','Vanilla fudge ripple','White', '2.6%'],
['10','Praline pecan','Brown','1.7%'],
['11','Cherry','Red','1.6%'],
['12','Chocolate almond','Brown','1.6%'],
['13','Coffee','Dark brown', '1.6%'],
['14','Rocky road','brown', '1.5%'],
['15','Chocolate marshmallow','Light brown','1.3%']
];

var el = document.getElementById('container');

var o = new WebFXColumnList();
o.create(el, aColumns);
o.addRows(aData);

Sample taken from http://webfx.eae.net/dhtml/collist/usage.html


Right now I have a DataSet, so I need to convert it to these arrays and the best way to do it is with xslt.
Because I want more than just column names returned to the client side, I’m going to use the Column Collection DataTable I created in the previous post for the aColumns array.

My XSLT will create the actual javascript vars, in the client side I'll simply evaluate the returned string and I'll have the variables ready to use

ConvertSearchResultsDS.xslt

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/" >

var aColumns = [<xsl:for-each select="*/Columns">
<xsl:sort select="Position" data-type="number" order="ascending"/>
{
<xsl:for-each select="./*">
<xsl:value-of select="name()"/>:'<xsl:value-of select="."/>'<xsl:if test="position() &lt; last()">,</xsl:if>
</xsl:for-each>
}<xsl:if test="position() &lt; last()">,</xsl:if>
</xsl:for-each>
];


var aData = [<xsl:for-each select="//Data">
[<xsl:for-each select="./*[name()=//Columns/Name]">
'<xsl:call-template name="escape-quotes">
<xsl:with-param name="text" select="normalize-space(text())"/>
</xsl:call-template>'<xsl:if test="position() &lt; last()">,</xsl:if>
</xsl:for-each>]<xsl:if test="position() &lt; last()">,</xsl:if>
</xsl:for-each>
];
</xsl:template>


<xsl:variable name="quote-char">
<xsl:text>'</xsl:text>
</xsl:variable>

<xsl:variable name="escaped-quote">
<xsl:text>\'</xsl:text>
</xsl:variable>


<xsl:template name="escape-quotes">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text,$quote-char)">
<xsl:variable name="pre" select="substring-before($text,$quote-char)"/>
<xsl:variable name="post">
<xsl:call-template name="escape-quotes">
<xsl:with-param name="text" select="substring-after($text,concat($pre,$quote-char))"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="concat($pre,$escaped-quote,$post)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>




I'm going to do the transformation in the web service.
I called the method GetResultString and in the web method code from part 1 I already called it.

protected string GetResultString(DataSet ds, int pageSize)
{
string result = TransformXsl(ds, "~/XSLT/ConvertSearchResultsDS.xslt");
int rowCount = (int)ds.Tables["TotalRows"].Rows[0]["TotalRows"];
result += String.Format("var TotalPages = {0};", CalculateTotalPages(rowCount, pageSize));

return result;
}



TransformXsl is a simple function that takes the dataset and xslt and does the transformation using the XslCompiledTransform class.
CalculateTotalPages returns the number of total pages using the total row count and page size


Displaying the grid

The JavaScript Search function that calls the web method defined a function called onComplete for the callback.
This function will receive the results string, create the WebFXColumnList object, initialize it and add the rows.

function onComplete (result) {
eval(result);

if (typeof(aColumns)!="undefined") {
var el =$get("searchResultsContainer"); //the element that will contain the grid
var searchResultsObject = new WebFXColumnList();
searchResultsObject.create(el, aColumns);
searchResultsObject.addRows(aData);
} else {
alert('No results returned');
}
}


After evaluating the returned javascript code I should have the aData and aColumns variables and from that point I can continue with the create and addRows method calls to display the grid.

The string created by the xslt is not exactly what the WebFXColumnList expects, so I'll need to make some changes to the javascript.

The create method of the ColumnList expects a simple array with names, so I need to go through it and change all references to aColumns.
I replaced the aColumns[i] to aColumns[i].Header when creating the head table.

I also need to add support for hidden columns, I want the create method to skip these. I need to add support for the formatting in the addRows function, and make sure everything else works.

I'm not going to go into all of these changes, but an updated script will be included in the download.


Files:

AjaxSearchSamplePart4.zip (919.09 kb)

 

Tags: , ,

AJAX | Asp.Net | Javascript

About Me

Ishai Hachlili is a web and mobile application developer.

Currently working on Play The Hunt and The Next Line


Recent Tweets

Twitter October 23, 05:22
@BenThePCGuy a standard where that doesn't matter is better. One more reason to get the #Lumia920, wireless charging, no need for microUSB

Twitter October 23, 05:21
@ManMadeMoon where they dance around the issues and don't really talk about them

Twitter October 23, 05:20
@BenThePCGuy are you a @wpdev ?

Twitter October 23, 04:17
@JonahLupton But if it's black it's usually better

Twitter October 23, 02:58
@jongalloway next time ask your 5 year old how to spell

@EShy