Dataviewer Library

... needs description

What it is

DataViewer is a library that helps manage display for search results. This is most often for tables, but it can display lists as well. Essentially the purpose of this library is to give you one method of interacting with and displaying your data, regardless of source.

What it does

  • Execute a search using Kinetic Bridges OR take input from other searches OR it can take input from fields on the screen
  • Display search results in a consistent format (DataTable and Unordered Lists included.)
  • Easy to implement
  • Consistent, reusable configuration driven.
  • Commonly used behaviors and functionality included in library's core functionality
  • The ability for the developer to insert custom behavior, through callbacks, at several points in the data search, display and selection.
  • Field values can be set upon user selection of results

How it helps your implementation

DataViewer is a library which provides a reusable and constant way to build search functionality into a form and display the results. Commonly used behavior is included in the functionality (ie: Set field values in a row or list selection), and results can be displayed as a Table or List. Custom Renderers may also be created to display search results in an alternate format. The library is configuration driven, reducing the need to create JS when creating simple tables from search results.

Install Information

NOTE: dataViewer is included in the default bundle provided by Kinetic Data.

Download

The dataViewer.js can be found on GitHub: https://github.com/KineticCommunity/library-dataviewer-ce

Requirements

  • dataViewer.js file
  • A JSON Schema to define the Data Viewer Configuration (in the item leveraging dataveiwer)
  • There may be additional requirements for Renderers that are used. Ex. the DataTables libraries from datatables.net for the table capability.

Include JavaScript and CSS

The recommended practice for including JavaScript and CSS files, such as dataViewer.js, is to add them to the header of layout.jsp or whatever file is rendering your services. Including files here will ensure the are accessible to all Kinetic Request Forms within the Bundle.

Usage Information

Bridged Resources

For the use cases involving searching, Bridged Resource defines the search and data returned from it. One must be added to the Kinetic Request Form, if planning to use the executeSearch function for dataViewer. The Data Viewer configuration will reference the Bridged Resource which was created.

Configuration

The searching and displaying of data is defined and configured, by the form developer, in a JSON Schema. It contains the necessary information to define the Bridge used by the search, how to render the results and the behavior. This configuration will be passed to dataViewer as a parameter to execute the search.

Multiple configurations can be created and included in a Kinetic Request Form.

Data Viewer Configuration Options are detailed below.

Renderers

There are 2 Renderers included with Data Viewer. The Renderers are part of the Configuration and used to determine how the search results will be displayed. There is also the option to use a custom Renderers to meet any unique requirements.

  • DataTable Render
  • Unordered List Render
  • Custom - A custom function can be created and included in the Configuration to handle the search results.

Execution

Data Viewer provides the following functions

FunctionDescription
DataViewer.ucFirst(str)Returns the provided string with the first letter uppercased
DataViewer.executeSearch(destination, configObj)Executes the bridge search provided in the config object, the formats the search results as provided in the config object, and displays those results using the renderer in the config object in the destination specified.
DataViewer.renderFieldValues(destination, configObj)Adds the values from the fields specified in the configuration into the table/object specified. See image below for example.
DataViewer.renderResults(destination, configObj)formats the search results that are in the config object as provided in the config object, and displays those results using the renderer in the config object in the destination specified.

Example of setup that uses renderFieldValues:
RenderFieldValues

Destination (JQuery Object, JQuery Selector, or function).

Destination defines the location of where the search results (Table or List) are to be appended on the page. The Destination may be supplied as a JQuery Object, JQuery Selector, function. If a function is provided, it must return a JQuery Object. (This is not the resultscontainerId specified in the Configuration but is where this element will be placed on the page.)

Configuration Object (JSON Object)

This is the Data Viewer Configuration Options created above in a JSON Object to define the behavior of the Data Viewer.

Examples:

//JQuery Selector
DataViewer.executeSearch('#Requested_For', searchConfig.personSearchBridgeTable);
//JQuery Object
DataViewer.executeSearch($('#Requested_For'), searchConfig.personSearchBridgeTable);

OR

DataViewer.renderFieldValues($(K('section[Results Section]').element()), searchConfig.personSearchBridgeTable);
//Function
DataViewer.executeSearch(function(){ return $(K('section[Requested For]').element());}, searchConfig.personSearchBridgeTable);

Styling

Custom styling may be applied to the results through the use of CSS. See Renderers for more information.

Configuration Option Details

  • resource: (nested JSON schema)
    • name:(String) Name of Bridge Resource
    • parameters: (Not used)
  • data: (Array of 1 or more nested JSON schemas) When using DataTabes column options may be passed through to it.  More info at https://datatables.net/reference/option/columns
    • name: (String) Name matches to data returned in the results
    • title: (String)(Optional) Title is used for display purposes to identify the data to the user
    • visible: (Boolean)(Optional) whether the item displays in the result or is hidden, defaults to true
    • className: (String)(Optional) HTML class of the values DOM element
    • setField:(String)(Optional) A field on the Form to receive the selected value upon click.
    • defaultContent: (String) (Optional) A text or HTML string that will be the defaulted value in the displayed results.  The value here will appear will all results sets.  This can be used when the data to be displayed doesn't come from the search results.
    • render: (Function ( data, type, record )) (Optional) Used to modify the value of the data before display.  The results returned from this function will be displayed in the results.  
  • renderer: (nested JSON schema)
    • type: (Function) A function to render the results of the search. "KDSearch.Renderers.DataTables" and "KDSearch.Renderers.UnorderedList" included with the library.  A custom function may also be supplied instead.
    • options: (Nested JSON schema) Values supplied here are specific to the Renderer and define the behavior of the Renderer.
      • before: (Function)(Optional) A function to execute before the search is performed
      • success: (Function)(Optional) A function to execute after the search is performed but before processing the data
      • successEmpty: (Function)(Optional) A function to execute after the search is performed when no results are returned
      • error: (Function)(Optional) A function to execute when an error is returned from the search
      • complete: (Function)(Optional) A function to execute after the search is performed and after the results are processed.  Executes after success and error.
      • clickCallback: (Function) (Optional) A function to execute when the results are clicked. Returns element click (jQuery Obj), selected results (JSON)
      • resultsContainerId: (String) Supply an arbitrary value which will be applied to the DataTable element id when it is created.   This value is be applied to the id attribute of the DataTable. Example:resultsContainerId: 'sampleTable' will result in: <table id="sampleTable" >
      • removeOnClick: (Boolean)(Optional defaulted "true") "true" or "false"  value to indicate if the search results should removed from display after a result is clicked.

Note that options not directly used by dataViewer will be passed on, unmodified, to the renderer used. This is particularly useful when other libraries, such as dataTables, are being used for the renderer.

Examples

Below is a configuration would be used with the renderResults function, because it has no bridge information and cannot be used with execute search (unless that is passed in dynamically).

searchConfig.addressTable = {
  resource: {
    name: ""
  },
  resultsContainer:
    '<table cellspacing="0", border="0", class="table table-striped table-bordered table-condensed dataTable">',
  data: [
    {
      name: null,
      orderable: false,
      className: "select-checkbox",
      defaultContent: "",
      width: "30px"
    },
    {
      title: "id",
      name: "address.id",
      visible: false
    },
    {
      title: "Location Name",
      name: "address.siteLocationName",
      orderable: true
    },
    {
      title: "GEOLOC Code",
      name: "geoloc.code",
      visible: true
    },
    {
      title: "Address",
      name: "address.streetAddress",
      visible: true
    },
    {
      title: "City",
      name: "address.city",
      visible: true
    },
    {
      title: "State",
      name: "address.state.abbreviation",
      visible: true
    },
    {
      title: "Zip Code",
      name: "address.zipCode",
      visible: true
    },
    {
      title: "Country",
      name: "address.state.countryId",
      visible: true
    }
  ],
  resultsContainerId: "address-table",
  before: function before(configObj) {},
  success: function success(configObj) {},
  error: function error(configObj) {},
  complete: function complete(configObj) {},
  removeOnClick: false,
  renderer: {
    type: DataViewer.Renderers.DataTables, // Passing a function here allows for better customization
    options: {
      // Options for Reneder
      processSingleResult: true,
      // DataTable OPTIONS; Passing options here make it clear that they are being passed to data tables
      // responsive: OPTIONAL Default for "BridgeDataTable" is true but can be over written.
      responsive: false,
      dom: "ftip",
      order: [[2, "asc"]],
      paging: true,
      pageLength: 20,
      lengthChange: false,
      deferRender: true,
      scrollCollapse: true,
      select: {},
      createdRow: function createdRow(row, data, dataIndex) {},
      initComplete: function initComplete() {}
    }
  }
    },

This example does have a bridge config and executed as shown below the configuration:

//put existing, formatted info into the search config
 searchConfig.addressTable.response = addrArray;
 //render this information
 DataViewer.renderResults(function() {
     return $(K('content[Addr Table]').element());
 }, searchConfig.addressTable);


 searchConfig.personTable = {
     resource: {
         name: 'people by Organization Id'
     },
     resultsContainer: '<table cellspacing="0", border="0", class="table table-striped table-bordered table-condensed dataTable">',
     data: [{
         title: 'id',
         name: 'id',
         visible: false,
     }, {
         title: 'Title',
         name: 'title'
     }, {
         title: 'Name',
         name: 'fullName',
         render: function render(data, type, row) {
             if (type === "display") {
                 if (row['IsNew'] && row['IsNew'] !== 'true') {
                     return data + " <i style='color:purple;' class='fa fa-user' aria-hidden='true'></i>";
                 } else if (bundle.helpers.nonRefDataExcludeUsers.indexOf(row['userId']) < 0) {
                     return data + " " + bundle.helpers.createNonRefDataTooltip({
                         "dateCreated": moment(row['dateCreated']).format('YYYY-MM-DD HH:mm:ss.SSS'),
                         "dataModified": moment(row['dataModified']).format('YYYY-MM-DD HH:mm:ss.SSS'),
                         "userFullName": row['userId'],
                         "userOrg": row['userOrg'],
                         "userRole": row['userRole']
                     });
                 } else {
                     return data;
                 }
             } else {
                 return data;
             }
         }
     }, {
         title: 'Organization',
         name: 'Org',
     }, {
         title: 'Action',
         name: null,
         render: function render(data, type, row) {
             var buttons = "<div class='action-buttons'><button class='action-button action-button-view btn btn-xs'>View</button> <button class='action-button action-button-remove btn btn-xs'>Remove</button></div>";
             return buttons;
         }
     }],
     resultsContainerId: 'person-table',
     before: function(configObj) {
         $('.message').show();

     },
     error: function(configObj) {},
     complete: function(configObj) {
         $('.message').hide();
         $(K('content[Person Table]').element()).find('.message').hide();

         //repopulate Person Summary that holds the JSON data representing the table.
         K('field[Person Summary]').value(JSON.stringify(configObj.tableObj.data().toArray()));
         K('field[Person Summary]').trigger('change');

         // On View Button
         configObj.tableObj.on('click', 'button.action-button-view', function() {
             var row = $(this).parents('tr'),
                 data = configObj.tableObj.row(row).data();
             bundle.helpers.personReview(data);
         });

         // On Remove Button
         configObj.tableObj.on('click', 'button.action-button-remove', function() {
             var row = $(this).parents('tr'),
                 data = configObj.tableObj.row(row).data();
             configObj.tableObj.row(row).remove().draw();
             //repopulate Person Summary that holds the JSON data representing the table.
             K('field[Person Summary]').value(JSON.stringify(configObj.tableObj.data().toArray()));
             K('field[Person Summary]').trigger('change');
         });
     },
     removeOnClick: false,
     renderer: {
         type: DataViewer.Renderers.DataTables, // Passing a function here allows for better customization
         options: {
             // Options for Render
             processSingleResult: false,
             // DataTable OPTIONS; Passing options here make it clear that they are being passed to data tables
             // responsive: OPTIONAL Default for "BridgeDataTable" is true but can be over written.
             responsive: false,
             dom: 'tip',
             order: [
                 [3, 'asc']
             ],
             paging: false,
             scrollY: '60vh',
             scrollCollapse: true,
             select: {
                 style: 'single',
                 selector: 'td:first-child'
             },
             createdRow: function createdRow(row, data, dataIndex) {
                 $(row).find('a[name="nonRefData"]').popover({
                     trigger: 'hover',
                     container: 'body'
                 });
             },
             deferRender: true,
         }
     }
 }
 };

Example calls for the above configuration:

  DataViewer.executeSearch(function () {
  return $(K('content[person Table]').element());
  }, searchConfig.personTable);

or this way

  searchConfig.personTable.response = pocArray;
   DataViewer.renderResults(function () {
  return $(K('content[person Table]').element());
  }, searchConfig.personTable);