In this article, I will demonstrate how to use YUI DataTable and DataSource to create a page that lets users search client records by client's first name, last name, and ID. If any client record is found, we display the search results in a table on the same page.
For DataSource, I use ScriptNodeDataSource. One of the major advantages of the ScriptNodeDataSource is that its data requests can be sent across domains by using JSONP (JSON Padding) instead of XHR. More discussions about JSONP can be found here.
First, let's define a ScriptNodeDataSource and response schema.
// Setup remote data source var ds = new YAHOO.util.ScriptNodeDataSource( 'http://www.anotherdomain.com/search/'); // The response JSON will have a results array // Each result object has userId, firstName, lastName, birthDate, // address1, address2, address3, city, state, and zip properties. ds.responseSchema = { resultsList: "results", fields: [ "userId", "firstName", "lastName", "birthDate", "address1", "address2", "address3", "city", "state", "zip" ] };
Define table columns. Use column formatters for column name, date, and address. Sort table rows by names.
// // Column formatters // // Format column Name var formatName = function(elCell, oRecord, oColumn, oData) { // Concat the last name and first name var strName = oRecord.getData("lastName") + ", " + oRecord.getData("firstName"); // Wrap name in a link that goes to client details page var strUserId = oRecord.getData("userId"); elCell.innerHTML = '<a href="' + getResultUrl(strUserId) + '">' + strName + '</a>'; }; // Format column DOB var formatDate = function(elCell, oRecord, oColumn, oData) { if (YAHOO.lang.isString(oData)) { if (Y.env.ua.ie > 0) { // IE has problem to parse date string "yyyy-mm-ddT00:00:00" // Here, we fall back to manipulating the date string elCell.innerHTML = oData.split("T")[0].replace(/-/g, "/"); } else { var oDate = new Date(oData); elCell.innerHTML = oDate.format("mm/dd/yyyy"); } } }; // Format column Address var formatAddress = function(elCell, oRecord, oColumn, oData) { var strAddr = oRecord.getData("address1") + " " + oRecord.getData("address2") + " " + oRecord.getData("address3"); strAddr = strAddr.trim() + ", " + oRecord.getData("city") + ", " + oRecord.getData("state") + " " + oRecord.getData("zip"); elCell.innerHTML = strAddr; }; // // Sorters // // Sort by name var sortName = function(a, b, desc) { var fnComp = YAHOO.util.Sort.compare; var compState = fnComp(a.getData("lastName"), b.getData("lastName"), desc); if (compState == 0) { compState = fnComp(a.getData("firstName"), b.getData("firstName"), desc); } return compState; }; // Column definitions var colDefs = [ { key: "name", label: "Name", resizeable: true, sortable: true, formatter: formatName, // formatName column formatter width: 120, sortOptions: { sortFunction: sortName } // sortName sort function }, { key: "address", label: "Address", resizeable: true, sortable: true, formatter: formatAddress, // formatAddress column formatter width: 250 }, { key: "birthDate", label: "DOB", resizeable: true, sortable: true, formatter: formatDate // formatDate column formatter }, { key: "userId", label: "Client ID", resizeable: true, sortable: true } ];
Setup table configuration. When the table is created, the data table will send out an initial request to get data. We want to capture this initial request, and prevent the server side from starting any search work, because at this moment our user hasn't filled any search keywords in the text fields yet (First Name, Last Name, and Client ID text fields). The initial request is not triggered by our users. It has to be filtered out. To do this, we append "&init=true" parameter to the initial request's URL so the server side will know.
// Table configurations var tableCfg = { initialRequest: "&init=true", sortedBy: { key: "name", dir: "asc" }, width: "100%", height: "30em", MSG_LOADING: "", MSG_EMPTY: "" };
The beef is here --- the search function which is responsible of gathering user inputs, validation, clearing previous search results in the table, constructing search queries, sending out query requests, displaying returned results, and handling errors.
// Field validation var validate = function(params) { // Validation logics go here ... return true; }; // Search function. // It will be invoked when users click the "Search" button var fnSearch = function(e) { // Suppress form submission YAHOO.util.Event.stopEvent(e); // Get search field values var params = { "firstName": document.getElementById("firstName").value, "lastName": document.getElementById("lastName").value, "userId": document.getElementById("userId").value }; // Field validations if (validate(params) == false) { return false; } // Callbacks for datasource.sendRequest var callbacks = { success: function(oRequest, oParsedResponse, oPayload) { console.log("Retrieved search results"); // Enable the table table.undisable(); // Flush and update the table content table.onDataReturnInitializeTable.apply(table, arguments); // Sort by name in ascending order table.sortColumn(table.getColumn("name"), YAHOO.widget.DataTable.CLASS_ASC); // Update the count of search results document.getElementById("results-count").innerHTML = " - " + oParsedResponse.results.length + " result(s)"; }, failure: function() { console.log("Failed to get search results"); // Failure handling code }, scope: table }; // Delete any existing rows, clear result count, // and disable the table table.deleteRows(0, table.getRecordSet().getLength()); document.getElementById("results-count").innerHTML = ""; table.disable(); // Construct search query var strQuery = ""; for(var key in params) { strQuery += "&" + key + "=" + params[key].trim(); } // Send out query request ds.sendRequest(strQuery, callbacks); console.log("Data source sent out request"); return false; };
Hook up the search function with the button click event. And finally, create the table.
YAHOO.util.Event.addListener("search-btn", "click", fnSearch); // Construct data table. Pass in column definitions, data source, // and table configuration var table = new YAHOO.widget.ScrollingDataTable("results-table", colDefs, ds, tableCfg); console.log("Constructed data table");