Search code examples
javascriptjsonsvelte

How to dynamically import json data using Svelte


I have previously been testing a component using the following code

<script>
import x from "/path/to/x.json"
</script>

this, as expected loads the json file to variable x.

What I would like to do, is dynamically load a local json file given an <input> element e.g.

<script>
let files ;
function loadJSONFile(){
  doSomething(files[0].name) ;
}
</script>

<input type="file" bind:files on:change={loadJSONFile}>

where doSomething() is doing the equivalent task of import in the first example.

Ideally, I could load the data from any local folder, so bind:files may not be appropriate, as files[0].name seems to yield a relative path, rather than an absolute path.


Solution

  • To read a user-provided file, you can use the FileReader API or the newer text() function from the Blob prototype. The best place to do that would be the change event.

    (If the user cancels the dialog, the files will be cleared.)

    <!-- using .text() -->
    <script>
        let json;
        
        async function onChange(e) {
            const file = e.target.files[0];
            if (file == null) {
                json = null;
                return;
            }
            
            json = JSON.parse(await file.text());
        }
    </script>
    
    <input type=file on:change={onChange} accept=".json"/>
    <pre>{JSON.stringify(json, null, '  ')}</pre>
    

    REPL

    <!-- using FileReader -->
    <script>
        let json;
        
        async function onChange(e) {
            const file = e.target.files[0];
            if (file == null) {
                json = null;
                return;
            }
            
            json = await readJsonFile(file);
        }
    
        function readJsonFile(file) {
            const reader = new FileReader();
            return new Promise((resolve, reject) => {
                reader.onload = () => resolve(JSON.parse(reader.result));
                reader.onerror = reject;
                reader.readAsText(file);
            });
        }
    </script>
    
    <input type=file on:change={onChange} accept=".json"/>
    <pre>{JSON.stringify(json, null, '  ')}</pre>
    

    REPL