1

I am a newbie programmer. I want to download json data from filtered json data that I have to CSV file. Here, my JSON API data:

The step should be like this:

  1. Pick date range from datepicker (example: 7May-8May)
  2. The filtered data will appear in inspect element using command console.log(filteredData)
  3. After that click the download button, and the filtered data (which is data from 7May-8May) will be downloaded.

I can do step 1 and step 2. But step 3 didn't work in my code. Anyone can help me with the code? Currently, this is my code: https://jsfiddle.net/estri012/2x3hmaLo/100/

$(function() {

$('input[name="datefilter"]').daterangepicker({
    showDropdowns : true,
autoUpdateInput: false,
locale: {
    cancelLabel: 'Clear'
}
});

$('input[name="datefilter"]').on('apply.daterangepicker', function(ev, picker) {
$(this).val(picker.startDate.format('YYYY-MM-DD') + ' - ' + picker.endDate.format('YYYY-MM-DD'));
var startDate = picker.startDate.format('YYYY-MM-DD');
var endDate = picker.endDate.format('YYYY-MM-DD');
if (startDate != '' && endDate != '') {
      console.log(startDate, endDate);
      var endpoint = 'https://gmlews.com/api/data/?node_id=1';

$.ajax({
method: "GET",
url: endpoint,
data: {
startDate: startDate,
endDate: endDate
},
success: function(data){
var data = data;
let filteredData = _.filter(data, function(data){ 
return (data.timestamp > startDate &&  
    data.timestamp < endDate)
});
console.log(filteredData);
} //function(data)end
}) //ajax end
} //if function end

$('input[name="datefilter"]').on('cancel.daterangepicker', function(ev, picker) {
$(this).val('');
});

}); //apply button end
//download button
$("#button1").on('click', function(e) {
// JSON to CSV Converter
    function ConvertToCSV(objArray) {
        var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
        var str = '';

        for (var i = 0; i < array.length; i++) {
            var line = '';
            for (var index in array[i]) {
                if (line != '') line += ','

                line += array[i][index];
            }

            str += line + '\r\n';
        }

        return str;
    }

    // Example
    $(document).ready(function () {

        // Create Object
        var filteredData = filteredData;

        // Convert Object to JSON
        var jsonObject = JSON.stringify(filteredData);


        // Convert JSON to CSV & Display CSV
        $('#button1').onclick(ConvertToCSV(jsonObject));
    });
})

}); //js function end

3 Answers3

1

Here is a working script,

What did I do?

  1. Removed the document.ready around the button, it was already in the document.ready
  2. Disabled the button until there actually WAS a filtered data
  3. Removed filteredData vars from all over the place and make it a global var
  4. Find the CDN for the JSON2
  5. Created a better csv converter (Quoting strings)
  6. Removed underscore and JSON2

let filteredData;
const ConvertToCSV = data => {
  if (!data || data.length === 0) { 
    console.log("data was empty");
    return;
  }
  let csv = [Object.keys(data[0]).slice(0).join(",")];
  data.forEach(
    item => csv.push(
      Object.values(item).map(val => isNaN(val) ? '"'+val+'"':val).join(",")
    )
  )
  csv=csv.join("\n");
  console.log(csv);
  const $link = $('<a/>',{ href: "data:text/csv;charset=utf-8,"+escape(csv), download:"filename.csv",text:"download"});
 
  $link[0].click(); // have to trigger native click
};
$(function() {

  $('input[name="datefilter"]').daterangepicker({
    showDropdowns: true,
    autoUpdateInput: false,
    locale: {
      cancelLabel: 'Clear'
    }
  });

  // Convert JSON to CSV & Display CSV
  $('#button1').on("click", function() {
    if (filteredData) ConvertToCSV(filteredData)
    else alert("Please get data first");
  }).prop("disabled", true);


  $('input[name="datefilter"]').on('apply.daterangepicker', function(ev, picker) {
    $(this).val(picker.startDate.format('YYYY-MM-DD') + ' - ' + picker.endDate.format('YYYY-MM-DD'));
    var startDate = picker.startDate.format('YYYY-MM-DD');
    var endDate = picker.endDate.format('YYYY-MM-DD');
    if (startDate != '' && endDate != '') {
      console.log(startDate, endDate);
      var endpoint = 'https://gmlews.com/api/data/?node_id=1';

      $.ajax({
        method: "GET",
        url: endpoint,
        data: {
          startDate: startDate,
          endDate: endDate
        },
        success: function(data) {
          filteredData = data.filter(item => item.timestamp > startDate && item.timestamp < endDate)
           console.log(filteredData);
           $('#button1').prop("disabled",false);
        } //function(data)end
      }) //ajax end
    } //if function end

    $('input[name="datefilter"]').on('cancel.daterangepicker', function(ev, picker) {
      $(this).val('');
    });

  }); //apply button end
  //download button

}); //js function end
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css" />


<ol class="breadcrumb">data from date : <input type="text" name="datefilter" value="" /></ol>
<p>Click this button to download all data from node 1</p>
<div>
  <button id="button1" type="button" class="button"><span>Download</span></button>
</div>

Test:

2020-05-03 - 2020-05-12

id,timestamp,vibration,moisture,gps_latitude,gps_longitude,gyro_x,gyro_y,gyro_z,accelero_x,accelero_y,accelero_z,displacement,node_id
83,2020-05-07T15:16:31.458380+07:00,2,30,-7.758856,110.376388,0.234,0.083,0.548,0.47,0.23,0.83,4,1
84,2020-05-07T21:14:19.171388+07:00,2,30,-7.758456,110.376388,0.34,0.83,0.48,0.47,0.23,0.83,4,1
mplungjan
  • 134,906
  • 25
  • 152
  • 209
0

The problem in the code was a simple discrepancy between the variable reference of "filteredData", as it was defined in multiple different scopes, without a global reference to the main one which it was supposed to be, after the ajax call was made. Secondly in the later part, there was a discrepancy between the onclick events of #button1, it only needs to be defined once. The following code is able to at least generate a JSON string after the dates are selected, and getting that into a CSV file is trivial, just map the array to comma separated values and stringify it. Anyways:

$(function() {

$('input[name="datefilter"]').daterangepicker({
        showDropdowns : true,
    autoUpdateInput: false,
    locale: {
        cancelLabel: 'Clear'
    }
});
let filteredData;
$('input[name="datefilter"]').on('apply.daterangepicker', function(ev, picker) {
    $(this).val(picker.startDate.format('YYYY-MM-DD') + ' - ' + picker.endDate.format('YYYY-MM-DD'));
var startDate = picker.startDate.format('YYYY-MM-DD');
var endDate = picker.endDate.format('YYYY-MM-DD');
if (startDate != '' && endDate != '') {
          console.log(startDate, endDate);
          var endpoint = 'https://gmlews.com/api/data/?node_id=1';

$.ajax({
  method: "GET",
  url: endpoint,
  data: {
    startDate: startDate,
    endDate: endDate
  },
  success: function(data){
  var data = data;
  filteredData = _.filter(data, function(data){ 
    return (data.timestamp > startDate &&  
        data.timestamp < endDate)
});
console.log(filteredData);
} //function(data)end
}) //ajax end
} //if function end

$('input[name="datefilter"]').on('cancel.daterangepicker', function(ev, picker) {
    $(this).val('');
});

}); //apply button end
//download button
$("#button1").on('click', function(e) {
// JSON to CSV Converter
        function ConvertToCSV(objArray) {
     //   console.log(typeof objArray, objArray)
            var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
      //      console.log("YO", array)
            var str = '';

            for (var i = 0; i < array.length; i++) {
                var line = '';
                for (var index in array[i]) {
                    if (line != '') line += ','

                    line += array[i][index];
                }

                str += line + '\r\n';
            }

            return str;
        }
        var jsonObject = JSON.stringify(filteredData);
     
    var csv = ConvertToCSV(jsonObject)
         var a = document.createElement("a")
         var blob = new Blob([csv])
         a.download = "test.csv"
         a.href = URL.createObjectURL(blob);
         a.click();
    
})

}); //js function end
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>


<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>

<script type="text/javascript" src="https://github.com/douglascrockford/JSON-js/raw/master/json2.js"></script>



    <ol class="breadcrumb">data from date : <input type="text" name="datefilter" value="" /></ol>
    <p>Click this button to download all data from node 1</p>
  <div>
    <button id="button1" class="button"><span>Download</span></button>
  </div>
bluejayke
  • 2,773
  • 2
  • 20
  • 50
  • how to make the button download work for downloading CSV file instead print it in the console? – Estri. P Lestari May 21 '20 at 06:22
  • if u want it to download then make a new A tag at the onclick event, set the download attribute to the tag, and the href to an object URL made to reference the CSV string.. I'll try to update it to show u – bluejayke May 21 '20 at 06:24
  • there is an error : Uncaught TypeError: Failed to execute 'createObjectURL' on 'URL': No function was found that matched the signature provided. – Estri. P Lestari May 21 '20 at 06:36
  • @Estri.PLestari its wokring now, just had to download the blob instead of txt – bluejayke May 21 '20 at 07:52
0

This should work: https://jsfiddle.net/maxim_mazurok/m23x7n04/16/

Learn more about JavaScript Scope

This was the main issue:

var filteredData = filteredData;
Maxim Mazurok
  • 2,730
  • 1
  • 16
  • 29