Estri. P Lestari
Estri. P Lestari

Reputation: 161

How to download CSV file from JSON data?

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

Upvotes: 2

Views: 3329

Answers (3)

mplungjan
mplungjan

Reputation: 178285

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

Upvotes: 1

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>

Upvotes: 0

Maxim Mazurok
Maxim Mazurok

Reputation: 4138

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

Learn more about JavaScript Scope

This was the main issue:

var filteredData = filteredData;

Upvotes: 0

Related Questions