Link to external file as in css o scripts but with database

Viewed 175

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.

3 Answers

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.

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();
    }
}

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.

Related