3

What I know

As we all know in HTML files we usually use

<head>
  <link rel="stylesheet" type="text/css" href="styles.css">
</head>

to link an external css stylesheet to a html file so this last one will be formatted as we need and also we use

<head>
  <script src="somescript.js"></script>
</head>

to make our html file use an external script.

Question

Is it possible to use the same approach by linking into a Viewer.html file an external file (or even more than one) to load from a simple database saved for example as csv, txt, db, json, xml, and so on?

HTML Pseudo code Example:

<head>
  <database src="somedata.db"></database>
</head>

Of course, once the data is available to the html file, a js will be used to put it where it has to go, for example into a table contained into the Viewer.html file.

Punctualizzations:

  1. No server of any kind must be involved, just only local files approach.
  2. No frameworks (no jquery, no Node...)
  3. I'm looking an approach that makes use just of html (HTML 5) + javascript (ES6) and the db file (*.csv, *.txt, *.json, *.xml, *.db, ...) containing only utf8 text. The records and fields in it will follow my specifics:
text field 1|text field 2|text field...|text field N
text field 1|text field 2|text field...|text field N
text field 1|text field 2|text field...|text field N

where the pipe symbol | is my custom field separator and the newline is the record separator.

willy wonka
  • 1,440
  • 1
  • 18
  • 31
  • I think that the JSON files can directly be imported inside of a javascript file from where we can use it. So why do you want to link it inside HTML ? – Tushar saxena Aug 07 '22 at 17:17
  • @Tusharsaxena for this approach I suppose I have to use a loader as Babel or Node. Am I wrong? with which I am not familiar with by the way. Also if I try the example at https://bobbyhadz.com/blog/javascript-import-json-file, I get the error **Access to script at 'file:///[...]/Test/Functions.js' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https.** This is due to the fact I am using local file with no server for my app. – willy wonka Aug 07 '22 at 17:30
  • No, you can also use it directly in the browser – Tushar saxena Aug 07 '22 at 17:31
  • @Tusharsaxena even if the browser is working with local files with no server intermediation? – willy wonka Aug 07 '22 at 17:34
  • You are right, CORS can be a real problem have you tried disabling it in the browser? – Tushar saxena Aug 07 '22 at 18:39
  • @Tusharsaxena, the app is not only for me it is also for others that don't like to mess with dangerous parameters for security reasons ; I will not do that. I hope to find another solution without messing with user security, even mine. Sorry. Also I want to allow the use of the app on different operative system and even different device type (computer, mac linux tablets smartphones and so on) the one thing they have in common is the standards ES6 HTML5 css3 : I will stick with that for principle and for security reasons and also for compatibility with systems and not high-end users. – willy wonka Aug 07 '22 at 19:01
  • So, do you want to load the data from the user's computer? Or the data you want to load is on the server that servers the HTML file? – Konrad Aug 21 '22 at 19:58
  • @KonradLinkowski 1) **No server of any kind must be involved, just only local files approach.** So basically the user, me or any one else, prepares the database that is basically a file containing text only data, properly organized into fields and records (csv or tsv like content) and the viewer has to properly show it. – willy wonka Aug 28 '22 at 12:54

3 Answers3

0

Try this solution if it feel your needs. It make use of json format:

index.html:

<html>
    <head>
        <script id="jsonDatas" type="application/javascript" src="./datas.json"></script>
        <script src="./index.js"></script>
    </head>
    <body onload="javascript:checkDatas();">
        <div id="datas"></div>
    </body>
</html>

datas.json:

let datas = [
    {"firstname":"alain","lastname":"deseine"},
    {"firstname":"robert","lastname":"dupont"},
    {"firstname":"john","lastname":"query"},
    {"firstname":"albert","lastname":"dumoulin"},
    {"firstname":"bob","lastname":"thesponge"}
];

index.js:

function checkDatas(){
    console.log('%o', datas);
}

With this solution you will have access of datas in local file datas.json.

UPDATE

This is the only way to achieve what you describe with local files.

Adding let datas... to datas.json is mandatory to make browser loading datas in a javascript var that you can access later. Browsers will blocks every attempt to access src loaded content for security reasons.

You can also use XMLHttpRequest or fetch to achieve what you want, but for this you need to serve your files with an HTTP server (which can be local). HTTP Server is required because file:// protocol is not supported by CORS. And CORS will block every requests originating from another server accordingly to CORS HEADERs that are set.

To bypass CORS with chrome browser, you can start chrome with thiese flags: --disable-web-security --user-data-dir see for details: Disable same origin policy in Chrome There is aloso some chrome extensions that block CORS (not tested). But ATTENTION, these solutions need user actions and they dramatically restrict browser security.

Alaindeseine
  • 3,260
  • 1
  • 11
  • 21
  • That's not JSON, and since you said `type="application/json"` the browser is going to insert the script element into the DOM and do nothing further. It certainly isn't going to make an HTTP request to the improperly labelled JavaScript or execute it. – Quentin Aug 17 '22 at 21:14
  • Actually this solution works as expected and the key of everything is: ** – willy wonka Aug 28 '22 at 17:03
  • [continues from the previous] ... **var db = `mydata table`** to make it work, which is also great because it will respect security in other users systems, doesn't matter of the browser. At the moment I see this as an almost perfect solution. Thank you **Alaindeseine**. Excellent job. – willy wonka Aug 28 '22 at 17:04
  • Using string literals with back ticks is not mandatory the use of json format: in fact I am experimenting with *.db or even *.csv and *.tsv and *.txt files: it works great too under the condition that the inner text of the file is enclosed into the variable and back ticks which is good enough. I wrote an answer too. – willy wonka Aug 28 '22 at 17:19
0

You can load the data using prefetch/preload in the link.

<link id="user_data" rel="preload"  as="fetch" crossorigin="anonymous"  href="user-data.json">

But your browser will not take any action on it and you can't access the loaded data in the javascript context.

In order to use the data in the javascript context, you have to call the fetch() function with the link URL. This will not load the data twice since the data is already preloaded on the page load.

function readData(selector){
    const link =  document.querySelector(selector) 
    if(link){
        return fetch(link.href)
        .then( res => res.json()) // use res.text() for XML or CSV 
    }else{
        throw 'Invalid selector on loadData(selector)'
    }
};

function abc(){
    //...
    readData('#user_data').then(data => { 
        console.log(data)
    })
    //...
}

Alternative solution

You can define your own custom element to get the desired feature

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="data-loader.js"> </script>  
    <!-- this script must be called before the custom element --> 
    
    <data-loader id="json" src="data.json" onload="onJSONFetch"></data-loader>
    <script src="script.js"> </script>
</head>
<body>
    <data-loader id="phone-xml" src="phone-number.xml" onload="onXMLFetch(event)"></data-loader>
    <data-loader id="user-data" src="user.csv"></data-loader>
</body>
</html>

data-loader.js

class DataLoader extends HTMLElement {
    constructor() {
        super();
    }
    connectedCallback() {
        this.load();
    }
    attributeChangedCallback(name, oldValue, newValue) {
        if (name === 'src') {
            this.load();
        }
    }

    load() {
        const attr = this.getAttribute('src');
        if (attr) {
            fetch(attr).then(res => res.text()).then((data) => {
                const event = new CustomEvent('load', { detail: data })
                this.dispatchEvent(event);
                
                const inlineEventHandlerName = this.getAttribute('onload');
                const cb = inlineEventHandlerName &&  window[inlineEventHandlerName];
                if((typeof cb) === 'function'){
                    cb(event);
                }
            })
        }
    }
}
customElements.define('data-loader', DataLoader);

script.js

const documentReady = () => {
    document.querySelector('#user-data').addEventListener('load', function (event) {
        console.log('user-data loaded', event.detail);
    })

}

function onXMLFetch(event){
    console.log('onXMLFetch', event.detail);
}
function onJSONFetch(event){
    console.log('onJSONFetch', event.detail);
}


document.onreadystatechange = () => {
    if (document.readyState === 'interactive') {
        documentReady();
    }
}
Sajan
  • 813
  • 9
  • 14
  • Hi, If I am not mistaken for security reasons **fetch()** doesn't work to get local files in a local environment with no server involvement, as well as **XMLHttpRequest();** . Am I wrong? – willy wonka Aug 28 '22 at 16:37
  • @willywonka You're right, fetch will use CORS and CORS is not applicable to local files. – Alaindeseine Aug 29 '22 at 07:44
  • @Alaindeseine in that case it will not work for my needs that are oriented to local data base files to handle... Sorry Sajan, but nevertheless thank you so much for your attempt. – willy wonka Aug 30 '22 at 14:29
0

Thanks to Alaindeseine's answer I got some inspirations and I did this: into any text file (so no necessarily *.json) I put these records (notice that the following is a template literal that makes use of back ticks `, not single ' or double " quotes):

var db =
`
my data field | my data field | my data field | my data field
my data field | my data field | my data field | my data field
my data field | my data field | my data field | my data field
`

Also because of the use of var instead of let, I have the advantage that the variable db gets hoisted so I can make use of it everywhere into the file and get its content from any other script or function. Also it can be potentially declared and overwritten multiple times after the previous one is elaborated so it will be also possible to queue multiple db files to show them into the same viewer.html, which is a great advantage, for my case at least.

I already tried this way with different text file types and works great. For example I've tested

*.json
*.tsv
*.csv
*.txt
*.db
*.ext
*(no extension at all)

So at this point I believe that this can also handle other generic files extensions, at the condition they contain text enclosed into a template literal, similarly to the above.

Of course into the html file I have to point/link to the database file as if it was a script like the following:

<script src="someDBfile.ext"></script> // This links the database
<script src="myJavascript.js"></script> //This links the javascript functions that get the data from the **db** variable and create the table/s to show the well formatted data contained into the database.

Nevertheless let's hope browser developers will implement in browsers a standard and more semantically correct way of doing this with an appropriate and semantically correct tag as

<database src="somedata.db"></database>

that works similarly. Also such procedure allows me to have just one Viewer.html to use to show all compatible files, which is also great.

willy wonka
  • 1,440
  • 1
  • 18
  • 31