Is there a way to convert a JSONObject to a .csv file in GWT?

I'm brand new to GWT, so please forgive me if this is a basic question, but I can't seem to find the solution. I have a function that works fine and allows me to export a table as .xlsx file. Everything is going smoothly with this process. I am using a third-party utility for this: https://github.com/stephenliberty/excel-builder.js/

However, my issue arises when I try to save the file as .csv format. I'm struggling to convert the GWT version of JSONObject (com.google.gwt.json.client.JSONObject.JSONObject()) to csv, and I can't find any helpful documentation on whether excel-builder-js supports csv exports or not. How can I achieve this?

    ...
            JSONObject object = new JSONObject();
            object.put("head", head);
            object.put("cols", columns);
            object.put("data", array);
            exportXlsxFromTable(JsonUtils.safeEval(object.toString()), GWT.getModuleName(), name);
    ...

    public static native void exportXlsxFromTable(JavaScriptObject originalData, String project, String name) /*-{
        var uri = 'data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,';
    $wnd
            .require(
                    [ project + '/excelbuilderjs/excel-builder', project + '/excelbuilderjs/Template/BasicReport' ],
                    function(EB, BR, downloader) {
                        var basicReport = new BR({
                            name : name
                        });
                        basicReport.setHeader([
                            {bold: false, text: name}, "", ""
                        ]);
                        var head = originalData['head'];
                        for (var i=0;i<head.length;i++) {
                            for (var j=0;j<head[i].length;j++) {
                                head[i][j].metadata = { type: 'string' };
                            }
                        }
                        basicReport.setData(head.concat(originalData['data']));
                        basicReport.setColumns(originalData['cols']);

                        var data = EB.createFile(basicReport.prepare());
                        
                        //          window.location.href = uri + data;
                        $entry(@com.mycompany.gxt.framework.view.dom.DOMUtils::downloadFile(Ljava/lang/String;Ljava/lang:String;)("myfile.xlsx", uri, data));
                    });
    }-*/;

public static native void downloadFile(String filename, String uri, String base64) /*-{
    var iframeDownloadFn = function(filename, uri, base64) {
        var values = {
            fn : 'b64d',
            fname : filename,
            fcont : uri + base64
        };

        try {
            $wnd.document.body.removeChild($wnd.downloadIframe);
        } catch (e) {
        }

        var iframe = $wnd.document.createElement("iframe");
        $wnd.document.body.appendChild(iframe);

        var iDoc = iframe.contentWindow.document;
        var form = iDoc.createElement("form");
        form.setAttribute("action", @com.mycompany.gxt.framework.client.FrameworkClient::DOWNLOAD_URL);
        form.setAttribute("method", 'POST');
        form.setAttribute("style", 'display: none');

        for ( var property in values) {
            if (values.hasOwnProperty(property)) {
                var value = values[property];
                if (value instanceof Array) {
                    for (var i = 0, l = value.length; i < l; i++) {
                        var el = iDoc.createElement("input");
                        el.setAttribute("type", 'hidden');
                        el.setAttribute("name", property);
                        el.setAttribute("value", value[i]);
                        form.appendChild(el);
                    }
                } else {
                    var el1 = iDoc.createElement("input");
                    el1.setAttribute("type", 'hidden');
                    el1.setAttribute("name", property);
                    el1.setAttribute("value", value);
                    form.appendChild(el1);
                }
            }
        }
        iDoc.body.appendChild(form);
        form.submit();
        $wnd.downloadIframe = iframe;
    }

    var clickLink = function(link, uri, base64) {
        var cancelled = true;

        try {
            if (document.createEvent) {
                var event = document.createEvent("MouseEvents");
                event.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
                cancelled = !link.dispatchEvent(event);
            } else if (link.fireEvent) {
                cancelled = !link.fireEvent("onclick");
            }
        } catch (e) {
            cancelled = true;
        }

        link.parentNode.removeChild(link);

        if (cancelled) {
            iframeDownloadFn(filename, uri, base64);
        }
    }

    var link = $wnd.document.createElement("a");
    link.setAttribute("href", uri + base64);
    link.setAttribute("name", filename);
    link.setAttribute("title", filename);
    link.setAttribute("download", filename);
    
    $wnd.document.body.appendChild(link);
    clickLink(link, uri, base64);
}-*/;

EDIT.:

After trying the suggestion from "Mon Mohon Singha" in JavaScript, I've reached this point:

  JSONObject object = new JSONObject();
object.put("head", head);
object.put("cols", columns);
object.put("data", array);

exportCsvFromTable(object.toString(), GWT.getModuleName(), name);

public static native void exportCsvFromTable(String originalData, String project, String name) /*-{
var uri = 'text/csv;charset=utf-8;';

function convertToCSV(jsData){
     var json = jsData;
     var fields = Object.keys(json[0]);
     var replacer = function(key, value) { return value === null ? '' : value }
     
     var csv = json.map(function(row){
       return fields.map(function(fieldName){
         return JSON.stringify(row[fieldName], replacer)
       }).join(',')
     })
     csv.unshift(fields.join(',')) // add header column
     return csv.join('\r\n');
}

var data = convertToCSV(originalData);

$entry(@com.mycompany.gxt.framework.view.dom.DOMUtils::downloadFile(Ljava/lang.String;Ljava.lang.String;)("export.csv", uri, data));

}-*/;

Unfortunately, I'm encountering this error, indicating that I might be using the wrong type...

com.google.gwt.logging.client.LogConfiguration
SEVERE: Exception caught: Exception caught: (TypeError) : json_0_g$.map is not a function com.google.gwt.event.shared.UmbrellaException: Exception caught: Exception caught: (TypeError) : json_0_g$.map is not a function
 at Unknown.fillInStackTrace_0_g$(as-0.js@3:130944)
 at Unknown.Throwable_3_g$(as-0.js@8:130899)
 at Unknown.Exception_3_g$(as-0.js@18:131042)
 at Unknown.RuntimeException_3_g$(as-0.js@18:287158)
 at Unknown.UmbrellaException_3_g$(as-0.js@25:313985)

EDIT2.:

This is the logged out JavaScriptObject, with some lines removed for clarity:

Object
cols: Array(10)
...
data: Array(100)
...
head: Array(1)
...
__proto__: Object

EDIT3.:

Following Rob Newton's advice, I updated the conversion function as below:

public static native void exportCsvFromTable(JavaScriptObject originalData, String project, String name) /*-{
        var uri = 'text/csv;charset=utf-8;';

        function convertToCSV(jsData){
              var json = jsData;

              var headerCSV = json.head[0].join(',');
              
              var rowsCSV = json.data.map( function(row) {
                return row.join(',');
              } );

              rowsCSV.unshift(headerCSV);

              console.log(rowsCSV.join('\r\n'));

              return rowsCSV.join('\r\n');
            }

            var data = convertToCSV(originalData);

            $entry(@com.mycompany.gxt.framework.view.dom.DOMUtils::downloadFile(Ljava.lang.String;Ljava.lang.String;)("export.csv", uri, data));

}-*/;

The converted data appears correct:

ID,NAME,FIRST NAME,BIRTHDAY,BIRTH PLACE,BIRTH COUNTRY,NATIONALITY,ORGANISATION,FUNCTION,PLACE
31471,Test,Test,07.05.2019,New,,,XYZ,ikl,
31470,John,Doe,03.03.1988,,,Canada,XYZ,,
31469,New,Test,25.03.1999,Right,USA,USA,,LA
...

However, the downloaded file is invalid, showing 0 bytes :(

Answer №1

Converting JSON data to CSV using JavaScript

If you're not familiar with GWT, it might be worth looking into as it could be helpful.

function jsonToCSVConverter(data){
      var jsonData = data;
      var fields = Object.keys(jsonData[0]);
      var replacerFunction = function(key, value) { return value === null ? '' : value }
      var csvData = jsonData.map(function(row){
        return fields.map(function(fieldName){
          return JSON.stringify(row[fieldName], replacerFunction)
        }).join(',')
      })
      csvData.unshift(fields.join(',')) // add header column
      return csvData.join('\r\n');
    }

function exportCSV(itemsData, fileName) {
        var csvData = jsonToCSVConverter(itemsData);
        var exportedFileName = fileName + '.csv' || 'export.csv';
        var blobData = new Blob([csvData], { type: 'text/csv;charset=utf-8;' });
        if (navigator.msSaveBlob) {
            navigator.msSaveBlob(blobData, exportedFileName);
        } else {
            var downloadLink = document.createElement("a");
            if (downloadLink.download !== undefined) {
                var urlLink = URL.createObjectURL(blobData);
                downloadLink.setAttribute("href", urlLink);
                downloadLink.setAttribute("download", exportedFileName);
                downloadLink.style.visibility = 'hidden';
                document.body.appendChild(downloadLink);
                downloadLink.click();
                document.body.removeChild(downloadLink);
            }
        }
        return true
    }

Answer №2

To successfully convert your data, make sure to pass a JavaScriptObject to the converter function instead of a string containing JSON. Here are some modifications you can make to your code:

exportCsvFromTable(object.getJavaScriptObject(), GWT.getModuleName(), name);

public static native void exportCsvFromTable(JavaScriptObject originalData, String project, String name) /*-{

Your object should have a property named head, which is an array with length 1. The first element of this array (head[0]) contains the names of your header columns. You can create a header line string like this:

var headerCSV = json.head[0].join(',');

The actual data rows are located in a property called data, which is an array. Each item in this array represents a row with its values stored in another array.

var rowsCSV = json.data.map(function(row) {
    return row.join(',');
});

You can then combine the header and rows as follows:

rowsCSV.unshift(headerCSV); // add header column
return rowsCSV.join('\r\n');

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Incorporating a File Attachment within a JSON Structure

Can a file attachment be included in a JSON Object? I am working on an HTML Form with text field inputs and a file attachment, and I would like to send all this form data (including the file attachment) as a JSON Object to the server. Are there any specif ...

Unable to integrate an if/else statement into the JSON reply

Working with an API to retrieve data and display images from it. I am attempting to implement an if/else statement that will show photos if the search term yields results in the response, and display a message indicating no results if it does not. Curren ...

Using JavaScript, add a complex JSON record to a JSON variable by pushing it

I have been attempting to insert a complex JSON data record into a JSON variable using the following code: var marks=[]; var studentData="student1":[{ "term1":[ {"LifeSkills":[{"obtained":"17","grade":"A","gp":"5"}]}, {"Work":[{"obtained":"13"," ...

The rows sent to HTML/Bootstrap from Java through JSON do not neatly wrap across rows evenly

I am having trouble getting images to wrap evenly on an HTML/Bootstrap page that are retrieved by Java and passed through JSON. Despite my expectations, there is a third row created with only one image and a fifth row with 3 extra images. Additionally, whe ...

Substitute the images with links provided in an external text file

I have a function that I use to replace avatars of players with custom images. Currently, I have three replacement links hardcoded into a Chrome extension. However, I want the function to read an external txt file to dynamically build an array so that I ca ...

Having trouble with the $push operator in Mongo DB?

I am facing an issue while attempting to store data in an array within an object in a Mongo model by utilizing the req.params method. Unfortunately, I encounter the following error: MongoError: cannot use the part (friends of friends.username) to traverse ...

Retrieve, process HTML table information using Ajax from an external server or website domain

In order to demonstrate: :the html table data source = "example.com/html_page_source" (tableid="source") :an xml file created from the specified table data = "pretendco.com/xml_built_from_html_table I am seeking guidance on how to build an xml file from ...

Is there anyone who can provide a comprehensive explanation for what is going on here?

{ // Let's figure out how to launch my HTML file as a webpage in Chrome. "version": "0.2.0", "configurations": [ { "type": "pwa-chrome", &q ...

Learn the process of dynamically populating an HTML table with data using JavaScript and JSON

I have developed a code snippet to dynamically add an HTML table without using jQuery. The code serves as an application from the server to the client, where the client receives a JSON object to parse into a string. Here is how you can add an HTML table ...

Engaging with JSON data inputs

Need help! I'm attempting to fetch JSON data using AJAX and load it into a select control. However, the process seems to get stuck at "Downloading the recipes....". Any insights on what might be causing this issue? (Tried a few fixes but nothing has w ...

Address Book on Rails

Hello, I'm relatively new to this and would be grateful for any assistance. My goal is to utilize the data saved by a user in their address book, and then offer them the option to use that address for delivery. Below is my Address controller: class A ...

Problem encountered when trying to show the Jquery Ajax response on an HTML page

I'm facing a challenge with loading a page that needs to display values with dynamic pagination. To retrieve these values, I am making a REST call which returns a JSON object. Although I can see the JSON output in the browser console, I am unable to d ...

Obtain HTML tags from RSS CDATA section

Is there a way to extract HTML tags from a CDATA tag in an RSS feed? I have utilized a basic jQuery function to retrieve the JSON object from the RSS, below is my code: $.get("someURL", function(data) { console.log('InGet'); ...

Learn the process of extracting a particular value from JSON data and displaying it in HTML by utilizing AngularJS's ng-repeat directive

As a newcomer to angularjs, I am encountering difficulties retrieving and displaying a specific value from a json file in order to showcase it on my view page using angularjs ng-repeat for image source. My goal is to repeat the json file based on a particu ...

How can you eliminate a specific element from an HTML document?

Utilizing localStorage can be tricky when it comes to keeping the JSON file hidden from being displayed on the HTML page. One approach I used involves sending the JSON file to the client once and then performing all logic using that file. To prevent the JS ...

Sending JSON Data from C# to External JavaScript File without Using a Web Server

Trying to transfer JSON data from a C# (winforms) application to a static HTML/JavaScript file for canvas drawing without the need for a web server. Keeping the HTML file unhosted is preferred. Without involving a server, passing data through 'get&ap ...

What is the best way to showcase nested array JSON data in an HTML Table?

https://i.stack.imgur.com/OHL0A.png I attempted to access the following link http://jsfiddle.net/jlspake/v2L1ny8r/7/ but without any success. This is my TypeScript code: var viewModel = function(data){ var self = this; self.orders = ko.observableArr ...

Utilizing JavaScript Fetch with User Input to Integrate OpenWeather API Retains Previous Data on HTML Page

I have been working with JavaScript Fetch to retrieve data from the OpenWeather API. In my project, I have created a form where users can input the name of a city to view its weather information. However, I am facing an issue where the data from the previo ...

Display the menu and submenus by making a request with $.get()

My menu with submenu is generated in JSON format, but I am facing issues displaying it on an HTML page using the provided code. Can someone please assist me in identifying what mistakes I might be making? let HandleClass = function() { ...

Is there a way to display multiple images in a JSON message object?

If you're looking for a fun way to generate random dog images, then check out my DogAPI image generator! Simply enter a number between 1-50 into the form text box, hit send, and watch as it displays that amount of random dog photos. I'm almost t ...