Skip to main content
Kinetic Community

Putting Answers into YUI Tables

The service item described in this article illustrates (also attached) a simple usage of using a customer's answers to build up a table in Kinetic Request.  This gives the customer to request multiple items (ex. Port details for a Server Add Request) without having to have multiple instances of the same field (ex. Port Type and IP Address) on the service item. The attached example is a very simple application of a clothing order.

Usage

The Description section below explains the service item implementation.  To try the service item that is being described, download the attached service item (in .zip format) and use the Kinetic Request Admin Console to import the service item into your environment.  The Service Item does not include category/catalog information, so it will need to be copied or moved to an existing catalog to be accessed.

The service item is available here.

Description

This example utilizes the YUI javascript library to automatically build the table from the Simple Data Request response.  

For more information about the YUI javascript library, see the Yahoo Developer Network: http://developer.yahoo.com/yui/

Sample Table

ExampleTable.png

This example displays a table of records obtained by the customer entering answers and submitting them as a row to the table. There are four steps necessary to configure a Kinetic Request service item to display a table of user answers:

  1. Require the javascript and css files necessary for YUI data tables
  2. Create the questions that have answers entered into the table and the table div
  3. Build the functions to process the tables
  4. Create the buttons for adding/removing rows and the events to support table build and save

1. Require the javascript and css files necessary for YUI data tables.

The following code was inserted into the customer header content for this service item to load the javascript and css files necessary for YUI datatables.

<script type="text/javascript" src="/kinetic/resources/js/yui/build/yahoo-dom-event/yahoo-dom-event.js"></script>
<script type="text/javascript" src="/kinetic/resources/js/yui/build/element/element-min.js"></script>
<script type="text/javascript" src="/kinetic/resources/js/yui/build/datasource/datasource-min.js"></script>
<script type="text/javascript" src="/kinetic/resources/js/yui/build/datatable/datatable-min.js"></script>

<link rel="stylesheet" type="text/css" href="/kinetic/resources/js/yui/build/datatable/assets/skins/sam/datatable.css" />
 
2. Create the questions that have answers entered into the table and the table div
 
The questions created depend entirely on what you data you need to collect. Any type of question can be used.
 
3. Build the functions to process the tables
 
The following code is in the "Javascript Code" element of the service item and is responsible for processing the table. The service item "Item Table" element includes the container element referenced by this code. There are a some of the functions defined to process the tables that can be shared functions. These shared functions can be used to process any number of tables, if the service item contains more than one table. These are:
  • buildTables()
  • saveTables()
  • deleteTableRows(table_str)
  • saveTable(table_obj, save_to)

Then, each table must have it's own function to build the table for display (this converts the saved JSON into an HTML object/table and places it into the specified div) and it's own function to add rows.

<script>

//define table variable
var tableItems;

/*******************Shared Table Functions*************************
** These functions can be extended to handle more than one table **
******************************************************************/

//Build the table for display on page load
function buildTables() {
    //Build the items table from the indicated stored JSON
    buildItemTable('itemsTableJSON', 'itemsTable');
}

//run saveTables before submit
function saveTables()
{
   var toReturn = true;
   if (!saveTable(tableItems, "itemsTableJSON")) toReturn = false;
   return toReturn;
}

//this function is to delete a row from a table
function deleteTableRows(table_str) {
    var selected = false;
    //Set the table to delete from
    switch(table_str)
    {
      case "tableItems" : table_obj = tableItems;
      break;
      }
    //Get the table object
    var tbl = table_obj.getTableEl();
    //determine which row is seleted
    var selIdx = 0;
    for (var x = 0; x < tbl.rows.length; x++) {
        if(table_obj.isSelected(x)) {
            selected = true;
            selIdx = x;
        }
    }
    if (selected == false)  {
        alert("No row selected");
    } else {
        //delete row
        table_obj.deleteRow(selIdx);
    }
}


function saveTable(table_obj, save_to) {
    //get the records for the given table object
    var records = table_obj.getRecordSet().getRecords();
    //store these records as a json string
    var str="[";
    for (var i=0; i < records.length; i++) {
        str= str+"{\"";
        var keys = table_obj.getColumnSet().keys;
        for (var j=0; j < keys.length; j++) {
            str= str+keys[j].getKey();
            str=str+"\":\"";
            str=str+records[i].getData(keys[j].getKey());
            if(j== (keys.length)-1) {
                if(i== (records.length)-1) {
                    str= str+"\"}";
                } else {
                    str= str+"\"},";
                }
            } else {
                str= str+"\",\"";
            }
        }
    }
    str=str+"]";
    //the size of the full answer field is 4000. We need to make sure
    //the table saved as a JSON string fits into the available space.
    var checkSize = str.length;
    if (checkSize > 4000) {
        //if the string is too long, alert and return false
        alert("There are too many rows in the table. This row will not be added.");
        return false;
    } else {
        //if the string isn't too long, save the table
        KD.utils.Action.setQuestionValue(save_to, str);
        return true;
    }
   
}

/********************End of Shared Table Functions**************************/

//Build the item table from the provided JSON string and display in provided
//div tag
function buildItemTable(jsonDataQuestion, divTag) {
    var oTxt = KD.utils.Action.getQuestionValue(jsonDataQuestion);
    //Either parse data or, if JSON is empty, set an empty datasource
    if (oTxt.length == 0) {
        var myDataSource = new YAHOO.util.DataSource([]);
    } else {
        var myDataSource = new YAHOO.util.DataSource(YAHOO.lang.JSON.parse(oTxt));
    }
    myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSARRAY;

    myDataSource.responseSchema = {
      fields: [
        { key: "item" },
        { key: "size" },
        { key: "color" },
        { key: "quantity" },
        { key: "comment" }
      ]
    };
   
  // CONFIGURE: The following variable defines which element the YUI data table
  //   will be inserted into and will need to be set to an element that exists
  //   in the service item.
  var containerElement = divTag;

  // CONFIGURE: The following variable defines what columns will be displayed in
  //   the table and will need to be configured for the specific Simple Data
  //   Response. Note that these are sortable columns

  var myColumnDefs = [
    {key:"item", label:"Item", sortable:true},
    {key:"size", label:"Size", sortable:true},
    {key:"color", label:"Color", sortable:true},
    {key:"quantity", label:"Quantity", sortable:true},
    {key:"comment", label:"Comment", sortable:true}
  ];

  // Ensure that the body element has the yui-skin-sam class so that the YUI
  // css classes for data tables are applied properly.
  YAHOO.util.Dom.addClass(document.body, 'yui-skin-sam');
 
  // Build the data table widget
  tableItems = new YAHOO.widget.DataTable(containerElement, myColumnDefs, myDataSource);
    tableItems.subscribe("rowMouseoverEvent", tableItems.onEventHighlightRow);
    tableItems.subscribe("rowMouseoutEvent", tableItems.onEventUnhighlightRow);
    tableItems.subscribe("rowClickEvent", tableItems.onEventSelectRow);
    tableItems.subscribe("theadLabelClickEvent", tableItems.onEventSortColumn);
}

//Add a row to the table
function addItemRow(use_key) {
    use_key = (typeof use_key == 'undefined')?true:use_key;
    var txtId = KD.utils.Action.getQuestionValue('Item');
    var txtSize = KD.utils.Action.getQuestionValue('Size');
    var txtColor = KD.utils.Action.getQuestionValue('Color');
    var txtQuantity = KD.utils.Action.getQuestionValue('Quantity');
    //Check that all required items are entered before allowing the row add
    //In this example, all columns are required except the comment
    if (txtId == '' || txtSize == '' || txtColor == '' || txtQuantity == '') {
        alert('Please fill in Item, Size, Color and Quantity before clicking add');
        return;
    }
    //Check the table to see if a duplicate row exists
    //In this example, there cannot be the same item, size, and color entered more than once
    //Note that if duplicates aren't a concern, you don't need this step
    len = tableItems.getTbodyEl().rows.length
    for(var i=0; i<len;i++){
        var iRecord = tableItems.getRecord(i);
        var iItem = iRecord.getData('item');
        var iSize = iRecord.getData('size');
        var iColor = iRecord.getData('color');
        if (iItem == txtId && iSize == txtSize && iColor == txtColor){
           alert('You have already added '+iSize+', '+iColor+' '+iItem+' to the table');
           return;
        }
    }
  
    //All checks passed, enter the given values into
    tableItems.addRow({item:txtId,
                       size:txtSize,
                       color:txtColor,
                       quantity:txtQuantity,
                       comment: KD.utils.Action.getQuestionValue('Comment')});
                      
    //Clear the previously selected options/reset defaults
    KD.utils.Action.setQuestionValue('Item', '');
    KD.utils.Action.setQuestionValue('Size', '');
    KD.utils.Action.setQuestionValue('Color', '');
    KD.utils.Action.setQuestionValue('Quantity', '1');
    KD.utils.Action.setQuestionValue('Comment', '');
   
    //Save the table. This checks to make sure they haven't exceeded the allowable table size.
    //If the save fails, build the table to visually clear the row that couldn't be saved.
     if (!saveTable(tableItems, "itemsTableJSON")) buildItemTable('itemsTableJSON', 'itemsTable');
   
}


</script>
 
4. Create the buttons for adding/removing rows and the events to support table build and save
 
The "Initial Page" element for this service item specifies the "Build Table" custom on-load event which initiates the table.  To create your own table, create a new load event with a Custom action.
 
BuildTableEvent.png
 
The buttons for adding and removing the rows to/from the table call the functions defined in the javascript referenced above. These are defined in the Table Buttons text element:
<input type="button"  value="Add Item to Table >>"  onclick="addItemRow();">
<input type="button" value="<< Remove Selected Row" onclick="deleteTableRows('tableItems');">
 
 
The "Initial Page" element for this service item specifies the "Save Table" custom beforeSubmit event which saves the table.  To save your own table, create a new beforeSubmit event with a Custom action. 
 

SaveTablesEvent.png