0
votes

I have a jquery function that renders an html table from a csv file. I would like to add a column to this table that contains a button for each row. The button will need to copy certain cells in the row to the clipboard.

The csv is generated through an ajax call and therefore the rows are not static. The rows of buttons should equal the rows in the csv. How do I add this column?

I am using the clipboard.js library but I have no idea where to begin. I understand that the text that needs to be copied should be id'ed so the library knows what to copy but how do I add the id to the row in the cell? Any suggestions would be greatly appreciated.

jquery function logs.js:

function clearString(str){
   var str = str.replace(/\"/g, "");
   return str;
  }
  function csvToTable(myReturn){
    var allRows = myReturn.split(/\r?\n|\r/);
    var table = '<table class="tablesorter">';
    for (var singleRow = 0; singleRow < allRows.length; singleRow++) {
      if (singleRow === 0) {
        table += '<thead>';
        table += '<tr>';
      } else {
        table += '<tr>';
      }
      var rowCells = allRows[singleRow].split(',');
      for (var rowCell = 0; rowCell < rowCells.length; rowCell++) {
        if (singleRow === 0) {
          table += '<th style="padding: 15px;">';
          table += clearString(rowCells[rowCell]);
          table += '</th>';
        } else {
          table += '<td>';
          table += clearString(rowCells[rowCell]);
          table += '</td>';
        }
      }
      if (singleRow === 0) {
        table += '</tr>';
        table += '</thead>';
        table += '<tbody>';
      } else {
        table += '</tr>';
      }
    }
    table += '</tbody>';
    table += '</table>';
    return table;
  }
  function showLogData(name, domElement, csv){
    csv = csv || false;

    var selStatus = jQuery('#txtselstatus').val();
    jQuery('#returndatalog').css('display', 'none');
    if (selStatus == "")
    {
      alert("Please enter status")
      jQuery('#txtselstatus').focus();
    }else
    {
      jQuery(domElement).html("<img src='/static/img/loader.gif'/>");
      jQuery.ajax({
        type: "POST",
        url: '/ajax/generatelogdata',
        dataType: 'json',
        data: {
            "chkstatus":"",
            'place_id': place_id,
            'queryname': name,
            'startDate': $("#reportrange").data('daterangepicker').startDate.format("YYYY-MM-DD"),
            'endDate': $("#reportrange").data('daterangepicker').endDate.format("YYYY-MM-DD")
        },
        success: function(response){
          ///console.log(response)
           jQuery('#returndatalog').css('display', 'block');

          if(typeof response =='object')
          {
            var myReturn = response.response;
            if (csv) {
                jQuery(domElement).html(csvToTable(myReturn));
                jQuery(domElement + " table").tablesorter();
            }
            else {
                jQuery(domElement).html(response.response.replace(/\"/g,""));
            }
          }
          if(response.error){

          }
          else{

          }
        },
        error:function(response){

        }
      });
    }
  }

html:

{% block css_includes %}
<link rel="stylesheet" href="/static/css/jquery-ui.css" type="text/css" />
<link rel="stylesheet" href="/static/css/tablesorter/style.css?rand=1" type="text/css" />
{% endblock %}
{% block js_includes %}
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript" src="/static/js/admin_stats.js?v={{version}}"></script>
<script src="/static/js/jquery-ui.js" type="text/javascript"></script>
<script  type="text/javascript"  src="/static/js/admin.js?v={{version}}"></script>
<script src="/static/js/handlebars.min-v1.1.2.js" type="text/javascript"></script>
<script  type="text/javascript"  src="/static/js/clipboard.min.js"></script>
<!-- datepicker add -->
<script type="text/javascript" src="//cdn.jsdelivr.net/jquery/1/jquery.min.js"></script>
<script type="text/javascript" src="//cdn.jsdelivr.net/momentjs/latest/moment.min.js"></script>
<script  type="text/javascript"  src="/static/js/jq.tablesorter.js"></script>
<script  type="text/javascript"  src="/static/js/logs.js?rand=9"></script>
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/bootstrap/3/css/bootstrap.css" />
<script type="text/javascript" src="//cdn.jsdelivr.net/bootstrap.daterangepicker/2/daterangepicker.js"></script>
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/bootstrap.daterangepicker/2/daterangepicker.css" />
{% endblock %}
{% block body %}
{% include "csr_header.html" %}
<!--Styles-->


    <!--Scripts-->
<script>
var place_id = ''; 
var startDate = '{{request.GET.start_date}}';
var endDate = '{{request.GET.end_date}}';

var clipboard = new Clipboard('.btn');

clipboard.on('success', function(e) {
    console.info('Action:', e.action);
    console.info('Text:', e.text);
    console.info('Trigger:', e.trigger);

    e.clearSelection();
});

clipboard.on('error', function(e) {
    console.error('Action:', e.action);
    console.error('Trigger:', e.trigger);
});

function init() {
    showLogData('globallogs_places', '#returngloballogsplaces', true);
}
</script>
<br>
<h3>Select a Date</h3>
<br>
<div id="reportrange" class="pull-left" style="background: #fff; cursor: pointer; padding: 5px 10px; border: 1px solid #ccc; width: 23%">
    <i class="glyphicon glyphicon-calendar fa fa-calendar"></i>&nbsp;
    <span></span> <b class="caret"></b>
</div>
<br>
<h3>Errors: Places</h3>
<div class="pull-right">
<a href="https://console.cloud.google.com/logs/viewer?" style="color:#60B7BA;
    font-size: 20px;
    margin-top: 0;
    padding-top: 11px;">View Logs</a>
</div>
<br>
<br>
<div id="returngloballogsplaces" align="left"></div>
<br>
<br>
<br>
{% endblock %}
2

2 Answers

3
votes

The clipboard.js plugin cares about binding the "what to copy" with the buttons using the data-clipboard-target attribute. So an id has to be defined inline.

You can do it using a unique id generated in the table creation loop, using the singleRow index.

Now, what's to be copied has to be an input... Not a td, because clipboard gets the text to copy using the value... Not the inner HTML.

You can style your input so it doesn't look like an input! Use the beginning of the id to style it. It is disabled in the generated markup I suggest.

input[id^='toCopy']{
  border:0;
  outline:0;
}

Then, you just have to instantiate the plugin on the button class. Here I strongly suggest you use a class that has no chance to be already used somewhere else. In their documentation, they suggest .btn... But that is way too common. I suggest .cb_btn (cb as in clipboard).

Below is your csvToTable function modified.
Notice the cellToCopyIndex index that you will have to check. It has to be a zero-based integer corresponding to the column you wish to copy.

function csvToTable(myReturn){

  var cellToCopyIndex = 2;  // The index of the cell to be copied, zero based

  var allRows = myReturn.split(/\r?\n|\r/);
  var table = '<table class="tablesorter">';
  for (var singleRow = 0; singleRow < allRows.length; singleRow++) {
    if (singleRow === 0) {
      table += '<thead>';
      table += '<tr>';
    } else {
      table += '<tr>';
    }
    var rowCells = allRows[singleRow].split(',');
    for (var rowCell = 0; rowCell < rowCells.length; rowCell++) {
      if (singleRow === 0) {
        table += '<th style="padding: 15px;">';
        table += clearString(rowCells[rowCell]);
        table += '</th>';
      } else {
        table += '<td>';
        if(rowCell==cellToCopyIndex){
          table += '<input type="text" id="toCopy_'+singleRow+'" value="'+clearString(rowCells[rowCell])+'" readonly>';
        }else{
          table += clearString(rowCells[rowCell]);
        }
        table += '</td>';
      }
    }
    if (singleRow === 0) {
      table += '</tr>';
      table += '</thead>';
      table += '<tbody>';
    } else {
      table += '</td><td><button class="cb_btn" data-clipboard-target="#toCopy_'+singleRow+'"><img src="assets/clippy.svg" alt="Copy to clipboard"></button></td></tr>';
    }
  }
  table += '</tbody>';
  table += '</table>';
  return table;
}

To instantiate the plugin, do it when the table is created... That is in your Ajax success callback:

success: function(response){
  ///console.log(response)
   jQuery('#returndatalog').css('display', 'block');

  if(typeof response =='object')
  {
    var myReturn = response.response;
    if (csv) {
        jQuery(domElement).html(csvToTable(myReturn));
        jQuery(domElement + " table").tablesorter();
        new Clipboard('.cb_btn');                       // Instantiate Clipboard here.
    }
    else {
        jQuery(domElement).html(response.response.replace(/\"/g,""));
    }
  }
  if(response.error){

  }
  else{

  }
},

Disclaimer: Fully untested!! ;)

1
votes

I have added an image that points out the places in your code where:

  • the rows start | This is a good spot for an id if you really need it...
  • the rows end | This is where you could add a cell with a button in it.

I think I wouldn't add ids... I'd detect the proper parent element of the button click and go from there.

A pic of your code with some arrows added...