1

I've created a page using a .csv file (comma delimited file) as the data source, but when I load the page an Invalid JSON response error is returned. When I check Network > XHR I can't see any error information and nothing is displayed under the Response tab. However, when I click on the OK button to dismiss the error message, all the data from the .csv file is displayed under the Response tab.

The same issue results whether I host the files locally or on my webserver.

Could this be an issue with a configuration in the https://cdn.datatables.net/1.10.25/js/jquery.dataTables.min.js file? I've provided the relevant header code I've used for reference below:

<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.25/css/jquery.dataTables.min.css">
<style type="text/css" class="init"></style>

<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script type="text/javascript" language="javascript" src="https://cdn.datatables.net/1.10.25/js/jquery.dataTables.min.js"></script>
<script type="text/javascript" class="init">
$(document).ready(function() {
    $('#mrgs').DataTable( {
        "ajax": 'mydata.csv'
    } );
} );
</script>

Does anyone have any ideas what could be causing this issue. Any assistance would be greatly appreciated.

ridgedale
  • 190
  • 1
  • 1
  • 14
  • 1
    CSV data is not JSON - they are completely different structures. DataTables expects JSON-structured data not CSV-structured data. Also, where is your `` element and where is the mapping from your data source to table columns?
    – andrewJames Jun 27 '21 at 13:46
  • There are various examples [here](https://datatables.net/examples/ajax/index.html) - do they help to clarify what you need to do? – andrewJames Jun 27 '21 at 13:46
  • Thanks for your reply andrewjames. There is nothing wrong with the table columns mapping: – ridgedale Jun 27 '21 at 14:41
  • Type Qtr Year Surname Forename(s) SpseName District Volume Page
    – ridgedale Jun 27 '21 at 14:41
  • The issue must be that a .csv file is not accepted. – ridgedale Jun 27 '21 at 14:43
  • You can [edit] your question to show the new information (the HTML in your comment). But just to clarify: The mapping I referred to is needed in the DataTables definition. It appears to be missing. (And, yes, DataTables expects JSON when handling an Ajax response). – andrewJames Jun 27 '21 at 14:50
  • It looks like the csv file needs to be converted to a json array and saved as a txt file if I've understood correctly. Am I on the right track? – ridgedale Jun 27 '21 at 14:51
  • There are several different ways to provide data to your DataTable. One way is to do what you are describing - but your browser will probably block your Ajax request with a CORS error if you try using `"ajax": 'mydata.txt'`. Did you look at the examples I linked to in my second comment? – andrewJames Jun 27 '21 at 14:59
  • And [here](https://datatables.net/examples/data_sources/index.html) are more ways, if you don't want to use Ajax. For example, using a JavaScript variable (an array of arrays, or an array of objects), or even simply hard-coded in the HTML. – andrewJames Jun 27 '21 at 15:01
  • Converting the csv file to json allowed the data to be displayed and the data to be filtered and sorted both locally hosted and on the webserver. No ajax issue was encountered. Is that likely to be a problem that other users could encounter when trying to load the pages? – ridgedale Jun 27 '21 at 15:40
  • I just noticed your comment/question "_Is that likely to be a problem...?_". Small tip: If you want to ping a commenter specifically, you can use the at-sign with a user ID (@andrewjames). First of all - I am glad you have a solution - that is great! Regarding the CORS issue, see [here](https://stackoverflow.com/questions/10752055/cross-origin-requests-are-only-supported-for-http-error-when-loading-a-local). I am surprised your local Ajax file URL worked. – andrewJames Jun 27 '21 at 19:23
  • Thanks for the tip and your assistance as well, andrewjames. – ridgedale Jun 29 '21 at 18:08

1 Answers1

1

You can preprocess your csv to be in the array of object values format DataTable wants.

Here is the complete solution ready to plug into your page

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href='https://cdn.datatables.net/1.10.25/css/jquery.dataTables.min.css' />
<script src="https://cdn.datatables.net/1.10.25/js/jquery.dataTables.min.js"></script>
<table id="mrgs" class="table"></table>
<script>
$(document).ready(function() {
    $.ajax({
        url: "./data.csv",
        context: document.body
    }).done(function(csv) {
        let allTextLines = csv.split(/\r\n|\n/);
        let headers = allTextLines[0].split(',').map(e => e.trim());
        let lines = [];
        for (let i = 1; i < allTextLines.length; i++) {
            let line = allTextLines[i].split(',') // take the comma separated line, turn into an array
                .reduce((b, a, index) => { // b is the accumulator, a is the iteration value
                    b[headers[index].toLowerCase().replace(/\s+/g, '')] = a.trim(); // set the object property and value
                    return b; // return the accumulator for our next iteration
                }, {});
        if (Object.keys(line).length === headers.length) lines.push(line)            }
        // now fix headers to be object/value pairs
        headers = headers.map((e) => ({
            title: e,
            data: e.toLowerCase().replace(/\s+/g, '')
        }))
        // console.log(headers)
        //  console.log(lines)
        $('#mrgs').DataTable({
            columns: headers,
            data: lines
        });
    });
});
</script>

$(document).ready(function() {
  let csv = `Type,Qtr,Year,Surname,Forenames,SpseName,District,Volume,Page 
  Marriages,Dec,1837,JAMES,Ann,,Mansfield,15,942 
  Marriages,Dec,1839,Karlton,Diana,,Mansfield,15,1017 
  Marriages,Dec,1841,Mepham,Elizabeth,,Mansfield,15,994 
  Marriages,Sep,1842,CASPIAN,Sophia,,Mansfield,15,617 
  Marriages,Dec,1842,Kennedy,Mark,,Mansfield,15,957
  Marriages,Dec,1843,Crampus,Elizabeth,,Mansfield,15,1034 
  Marriages,Mar,1846,Dalton,Paulina,,Mansfield,15,741 
  Marriages,Dec,1846,JAMIESON,William,,Mansfield,15,1031 
  Marriages,Dec,1848,Rodon,Reuben,,Mansfield,15,1096 
  Marriages,Mar,1849,PHILBERT,Reuben,,Mansfield,15,703 
  Marriages,Dec,1849,STARKEY,Thos,,Mansfield,15,1092 
  Marriages,Jun,1850,Porter,John,,Mansfield,15,843`
  let allTextLines = csv.split(/\r\n|\n/);
  let headers = allTextLines[0].split(',').map(e => e.trim());
  let lines = [];
  for (let i = 1; i < allTextLines.length; i++) {
    let line = allTextLines[i].split(',') // take the comma separated line, turn into an array
      .reduce((b, a, index) => { // b is the accumulator, a is the iteration value
        b[headers[index].toLowerCase().replace(/\s+/g, '')] = a.trim(); // set the object property and value
        return b; // return the accumulator for our next iteration
      }, {});
    if (Object.keys(line).length === headers.length) lines.push(line)
  }
  // now fix headers to be object/value pairs
  headers = headers.map((e) => ({
    title: e,
    data: e.toLowerCase().replace(/\s+/g, '')
  }))
  // console.log(headers)
  //  console.log(lines)
  $('#mrgs').DataTable({
    columns: headers,
    data: lines
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href='//cdn.datatables.net/1.10.25/css/jquery.dataTables.min.css' />
<script src="//cdn.datatables.net/1.10.25/js/jquery.dataTables.min.js"></script>

<table id="mrgs" class="table"></table>
Kinglish
  • 23,358
  • 3
  • 22
  • 43
  • Thanke for your reply Kinglish. It would definitely save time if I could avoid having to convert the files. However, when I replaced the document ready function code with your code and edited the url line to point to the csv file only the table header from the code is displayed. No data is displayed, no search field, no sort facility, no show x number of entries dropdown. What am I overlooking?
    – ridgedale Jun 27 '21 at 15:50
  • I updated my answer, the code and added an example snippet – Kinglish Jun 27 '21 at 16:03
  • I can see the code snippet works, but when I replace the code with: – ridgedale Jun 27 '21 at 19:28
  • $(document).ready(function() { $('#mrgs').DataTable( { let csv = `First name, Last name, Address, City, State, Zip John,Doe,120 jefferson st.,Riverside, NJ, 08075 Jack,McGinnis,220 hobo Av.,Phila, PA,09119 Stephen,Tyler,7452 Terrace At the Plaza road,SomeTown, SD, 91234, Blankman,,SomeTown, SD, 00298` – ridgedale Jun 27 '21 at 19:29
  • let allTextLines = csv.split(/\r\n|\n/); let headers = allTextLines[0].split(',').map(e => e.trim()); let lines = []; for (let i = 1; i < allTextLines.length; i++) { lines.push(allTextLines[i].split(',').map(e => e.trim())) } $('#mrgs').DataTable({ columns: headers, data: lines }); }); }) – ridgedale Jun 27 '21 at 19:29
  • No data is returned as previously. – ridgedale Jun 27 '21 at 19:29
  • What I noticed when I converted the csv file manually is that I had to wrap the output json text with { "data": } and then the converted csv data displayed. Could that be the issue? – ridgedale Jun 27 '21 at 19:33
  • I updated my example. There were a couple things that needed fixing. I commented some of the code. Pls check and if this answers your question, please accept the answer and consider an upvote for the effort. Thanks! – Kinglish Jun 27 '21 at 19:55
  • Thanks Kinglish. When I run your code using the let csv = statement and when I store the data in test.csv the four rows of data are displayed without any error as expected. However, when I use the same code and replace test.csv with my test data that has 174 rows including the header row I get the error: "DataTables warning: table id=mrgs - Requested unknown parameter 'qtr' for row 173, column 1." – ridgedale Jun 27 '21 at 21:23
  • I click OK to dismiss the error and the same error is presented again. I click OK again and then the data is displayed with a blank first row. I can't see anything wrong with the data and I've no idea why a blank first row is being returned. I suspect whatever is causing the initial blank row might be the issue. – ridgedale Jun 27 '21 at 21:23
  • Can you share your data source? I can't comment on what I cant see. – Kinglish Jun 27 '21 at 21:24
  • Either post a link to your data, or update your question with a sample of the data – Kinglish Jun 27 '21 at 21:24
  • $(document).ready(function() { $.ajax({ url: "mydata.csv", }).done(function(csv) { let allTextLines = csv.split(/\r\n|\n/); let headers = allTextLines[0].split(',').map(e => e.trim()); let lines = []; for (let i = 1; i < allTextLines.length; i++) { let line = allTextLines[i].split(',') // take the comma separated line, turn into an array .reduce((b, a, index) => { // b is the accumulator, a is the iteration value b[headers[index].toLowerCase().replace(/\s+/g, '')] = a.trim(); // set the object property and value – ridgedale Jun 27 '21 at 21:25
  • return b; // return the accumulator for our next iteration }, {}); lines.push(line) } – ridgedale Jun 27 '21 at 21:25
  • // now fix headers to be object/value pairs headers = headers.map((e) => ({ title: e, data: e.toLowerCase().replace(/\s+/g, '') })) // console.log(headers) // console.log(lines) $('#mrgs').DataTable({ columns: headers, data: lines }); }); }) – ridgedale Jun 27 '21 at 21:25
  • no. not that. Please share the data. the csv. is there a link to it? Or maybe you can copy a bunch `and add it to your question`. thanks – Kinglish Jun 27 '21 at 21:26
  • Seriously, can you copy the first 5 or six lines of it and put it in your question? Or share a link? I am leaving soon and want to wrap this up – Kinglish Jun 27 '21 at 21:30
  • No data is initially returned if I add 3 additional columns of data to your data. Here is some sample data: – ridgedale Jun 27 '21 at 21:57
  • Type,Qtr,Year,Surname,Forenames,SpseName,District,Volume,Page Marriages,Dec,1837,JAMES,Ann,,Mansfield,15,942 Marriages,Dec,1839,Karlton,Diana,,Mansfield,15,1017 Marriages,Dec,1841,Mepham,Elizabeth,,Mansfield,15,994 Marriages,Sep,1842,CASPIAN,Sophia,,Mansfield,15,617 Marriages,Dec,1842,Kennedy,Mark,,Mansfield,15,957 – ridgedale Jun 27 '21 at 21:57
  • Marriages,Dec,1843,Crampus,Elizabeth,,Mansfield,15,1034 Marriages,Mar,1846,Dalton,Paulina,,Mansfield,15,741 Marriages,Dec,1846,JAMIESON,William,,Mansfield,15,1031 Marriages,Dec,1848,Rodon,Reuben,,Mansfield,15,1096 Marriages,Mar,1849,PHILBERT,Reuben,,Mansfield,15,703 Marriages,Dec,1849,STARKEY,Thos,,Mansfield,15,1092 Marriages,Jun,1850,Porter,John,,Mansfield,15,843 – ridgedale Jun 27 '21 at 21:57
  • Thx - I'll add that to the answer – Kinglish Jun 27 '21 at 21:58
  • can you check your source - are those separated by line breaks? When I copy and paste your comment it all comes out on one line, which would change my solution. Please check – Kinglish Jun 27 '21 at 22:01
  • Yes, each line of data is separated by a line break. – ridgedale Jun 27 '21 at 22:15
  • Thanks, but I'm trying to parse a separate .csv file, not parse embedded comma delimited text in the php file. The text included is a tiny sample of the data. The intended csv files will include many thousands of rows of data and many more columns. Hence the reason for intending to use the $(document).ready(function() { $.ajax({ url: "mydata.csv", }).done(function(csv) { method. Is this simply not possible? – ridgedale Jun 27 '21 at 23:27
  • Of course, the snippet is just a demo of the functionality. I updated the answer to have the complete solution. You just need to change the URL where the csv is located. I tested it on my own server. – Kinglish Jun 28 '21 at 03:45
  • I've worked out that if the .csv file is saved in CSV UTF-8 (Comma-delimted) (.csv) format the error: "DataTables warning: table id=mrgs - Requested unknown parameter 'qtr' for row 173, column 1." is displayed. The error always relates to the last row of data irrespective of the number of records. If the file is saved in Comma-separated Values (.csv) format the table displays without error. – ridgedale Jun 28 '21 at 06:22
  • Ok, we're getting somewhere! I just added this line to the answer `if (line.length === headers.length) lines.push(line)` which will prevent the table from accepting rows that aren't completely filled (which appears to be the error you're getting). Can you try that? – Kinglish Jun 28 '21 at 06:25
  • Thanks for your patience, Kinglish. Replacing lines.push(line) with if (line.length === headers.length) lines.push(line) produces error alert but instead of the returned rows of data the following message is displayed in the table: No data available in table. – ridgedale Jun 29 '21 at 16:13
  • Ha, my bad. Forgot `line` was an object - fixed in answer and snippet with this : `if (Object.keys(line).length === headers.length) lines.push(line)` – Kinglish Jun 29 '21 at 16:29
  • That fixed the issue. :) Thank you kindly for all your assistance, Kinglsih – ridgedale Jun 29 '21 at 18:06
  • @ridgedale - Alright! That's great news. How about selecting this as the answer and giving it an upvote as well for the effort. Cheers – Kinglish Jun 29 '21 at 18:07
  • 1
    I was trying to work how to upvote and accpet the answer. It is quite frankly not obvious. As I now understand the person raising the question has to click the up-arrow (to the top left of the answer) to upvote the answer and click on the tick below the arrows to accept the answer. I hope that is correct. Many thanks again. – ridgedale Jun 29 '21 at 18:20
  • You did it. Thanks! I also upvoted your question as it's somewhat unique and required a few layers of solving – Kinglish Jun 29 '21 at 18:25