Skip to main content
Kinetic Community

Putting Answers into DataTables

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.

Description

This example utilizes the DataTable plugin for JQuery to automatically build the table from the answers.

For more information about DataTable, see this site. For more information about JQuery, see this site. There is also helpful information here.

Sample Table 

QuestionsTable.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 DataTables
  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 rows (note that delete is processed from within the table) and the events to support table build and review

1. Require the javascript and css files necessary for DataTables

The following code was inserted into the customer header content for this service item to load the javascript and css files necessary for footable datatables. Note that these are not local calls. To do this long term on your system, you would want to download these locally and reference them from the local source.


<meta name="viewport" content = "width = device-width, initial-scale = 1.0, minimum-scale = 1.0, maximum-scale = 1.0, user-scalable = no" />
<script type='text/javascript' src='//code.jquery.com/jquery-2.1.4.min.js'></script>
<!-- DataTables CSS-->
 <link rel="stylesheet" type="text/css" href="//cdn.datatables.net/1.10.7/css/jquery.dataTables.min.css"> 
  
<!-- DataTables-->
<script type="text/javascript" charset="utf8" src="//cdn.datatables.net/1.10.7/js/jquery.dataTables.min.js"></script>
<!-- JQuery UI-->
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.css" />
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>
<!-- Font-Awesome -->
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.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
 
Note that since there are click actions on the table, there is a section table build function for review request that doesn't contain the actionable items. Also, note that 5.2 and later doesn't require the 4000 character check since that restriction no longer exists on answers.
 

<style>
.questionLayer {
    margin: 0 2px 0 7px !important;
    float: left  !important;
}
/*Stlying for the Check Mark in the fooTable using Font Awesome.*/
.delete > i {
    color:red;
}
</style>
<script>

//define table variable
var tableItems;

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

//Build the item table from the provided JSON string and display in provided
//div tag
function buildItemTable(jsonDataQuestion, divTag) {
    //Set up table
    tableItems = $('<table  id="'+divTag+'" >').replaceAll($('#'+divTag));
    
     // create table
    tableItems =  $('#'+divTag).DataTable( {
    //allows you to recreate the table each time they click search/add row
     "destroy": true,
     responsive: true,
     //creates the columns for the table
    columns: [
                
                { data: 'Item', "title":"Item" },
                { data: 'Size', "title":"Size" },
                { data: 'Color', "title":"Color" },
                { data: 'Quantity', "title":"Quantity" },
                { data: 'Comment', "title":"Comment" },
                { data: 'delete', "title":"DELETE",    orderable: false, width: 60,            className: "delete " }
            ]
    });
    
    //get data and parse JSON
    var oTxt = KD.utils.Action.getQuestionValue(jsonDataQuestion);
    var json = "[]";
    var dataArray = [];
        if (oTxt != null && oTxt != "") {
        //append the table body to the existing header
        var thisRow = {};
        json = $.parseJSON(oTxt);
        //create body and append body to the table by looping through the JSON
        for(var i=0; i < json.length; i++){

            // add row
            thisRow = { 
            "delete": "<i class='fa fa-check-square-o'></i>",
           "Item": json[i].Item,
            "Size": json[i].Size,
           "Color": json[i].Color,
            "Quantity": json[i].Quantity,
            "Comment": json[i].Comment    };
            dataArray.push(thisRow);
    
        }
        
    }
     //clear any existing data from the table, add the built rows and draw the table
    tableItems.clear().rows.add(dataArray).draw();
    
    //set up delete on click
    $('#'+divTag).on( 'click', 'td', function () {
       var cell = tableItems.cell(this);
       //if they clicked on the delete cell
       if (cell.data() == "<i class='fa fa-check-square-o'></i>") {
          //remove the seleted row
            tableItems.row(this.parentNode).remove().draw();
            buildTableJSON(tableItems);
    
        }
    } );
}
//Build the item table from the provided JSON string and display in provided
//div tag
function buildItemTableReview(jsonDataQuestion, divTag) {
    //Set up table
    tableItems = $('<table  id="'+divTag+'" >').replaceAll($('#'+divTag));
    
     // create table
    tableItems =  $('#'+divTag).DataTable( {
    //allows you to recreate the table each time they click search
     "destroy": true,
     responsive: true,
     //creates the columns for the table
    columns: [
                
                { data: 'Item', "title":"Item" },
                { data: 'Size', "title":"Size" },
                { data: 'Color', "title":"Color" },
                { data: 'Quantity', "title":"Quantity" },
                { data: 'Comment', "title":"Comment" }
                
            ]
    });
    
    //get data and parse JSON
    var oTxt = KD.utils.Action.getQuestionValue(jsonDataQuestion);
    var json = "[]";
    var dataArray = [];
        if (oTxt != null && oTxt != "") {
        //append the table body to the existing header
        var thisRow = {};
        json = $.parseJSON(oTxt);
        //create body and append body to the table by looping through the JSON
        for(var i=0; i < json.length; i++){

            // add row
            thisRow = { 
           "Item": json[i].Item,
            "Size": json[i].Size,
           "Color": json[i].Color,
            "Quantity": json[i].Quantity,
            "Comment": json[i].Comment    };
            dataArray.push(thisRow);
    
        }
        
    }
     //clear any existing data from the table, add the built rows and draw the table
    tableItems.clear().rows.add(dataArray).draw();
    
}

//Add a row to the table
function addItemRowJson() {
    
    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;
    }
        
    //Get existing table values
    var existingTableJson = KD.utils.Action.getQuestionValue('itemsTableJSON');
    if (existingTableJson == "" || existingTableJson == null) {
        //The table is currently blank/empty. Create an empty json string to work with
        existingTableJson = "[]";
    } else {
        //entries already exist, so check that this isn't a duplicate.
        var duplicatesCheckReturn = true;
        $(jQuery.parseJSON(existingTableJson)).each(function() {  
             if (this.Item == txtId && this.Size == txtSize && this.Color == txtColor) {
                alert("You have already ordered "+txtColor+", "+txtSize+" "+txtId);
                duplicatesCheckReturn = false;
            }
        });
        if (duplicatesCheckReturn == false) { return; }
    }
        
    //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.
    
        
        //Add the row to the visible table
        tableItems.row.add({ 
            "delete": "<i class='fa fa-check-square-o'></i>",
            "Item": txtId,
            "Size": txtSize,
            "Color": txtColor,
            "Quantity": txtQuantity,
            "Comment": KD.utils.Action.getQuestionValue('Comment')    }).draw();
    
    buildTableJSON(tableItems);
    
    //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', '');
    
    
}    

function buildTableJSON(table){
    var newTableJson = JSON.stringify(table.rows().data().toArray());
    //This commented out section necessary for pre 5.2 versions. If pre 5.2 use this instead of the next line that isn't commented
    //var checkSize = newTableJson.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.");
    //    $('#itemsTable tr:has(td)').last().remove()
    //    return false;
    //} else {
    //    //if the string isn't too long, save the table
    //    KD.utils.Action.setQuestionValue('itemsTableJSON', newTableJson);
    //}
    KD.utils.Action.setQuestionValue('itemsTableJSON', newTableJson);
}

//Call this on a beforeSubmit event to ensure that there is at least one
//row in the table. 
function checkJsonString(jsonDataQuestion) {
     var json = KD.utils.Action.getQuestionValue(jsonDataQuestion);

     if (json == "" || json == "[]" || json.indexOf("No data available in table") != -1) {
          alert("You must enter at least one row in the User table before submitting your request.");
          return false;
     } else {        
          return true;
    }
}
</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.
 
BuildTablesEvent.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="addItemRowJson();">
For the review page, there are a couple of events, besides the build table, one to remove the questions and add items button:
 
RemoveForReview.png
And one load the review frame, just like you would load any review page. No special handling is required for the table when necessary loading the frame.
LoadReviewFrame.png