Home > Software engineering >  How can I import data using props with Svelte for this reusable gallery I'm building?
How can I import data using props with Svelte for this reusable gallery I'm building?

Time:03-24

I'm building a reusable gallery using Svelte. All else is done but I have multiple galleries so multiple sets of image data and I can't figure out how to pass the image data in as a prop. Anyways the code should better show what I mean.

I have a .js file for the image data:

//rocketgallery.js
export const images = [
    {
        id: 0,
        alt: "Zack and Alex arming a rocket.",
        src: "img/gallery/rocket1.jpg"
    },
    {
        id: 1,
        alt: "Zack and Matt performing parachute testing.",
        src: "img/gallery/rocket2.jpg"
    }
]

the gallery component itself (I'm just showing how I'd like to import the images [which obviously doesn't work]):

//slidegallery.svelte
    export let gallerydata = {gallerydata}
    import {images} from gallerydata

and the little snippet to insert a gallery:

//in index.svelte
  import Slidegallery from '$lib/components/slidegallery.svelte'

  <Slidegallery gallerydata='../data/rocketgallery.js' size='20vw' position='left' display='wrap'/>
  <Slidegallery gallerydata='../data/anothergallery.js' size='20vw' position='center' display='block'/>

So as you can see I'm trying to indicate what images I want in each gallery in the index page, and my component is looking to import the images from the path specified. I've been stuck on this for a bit so any direction would be a great help. I'm not sure if my entire approach to this is wrong or whether this is a simple syntax problem. Either way, pre-thank you!

CodePudding user response:

I think the images shouldn't be imported inside the component, but in index.html since you want to pass them as a prop. And it's an array of objects, so export let gallerydata = {gallerydata} is not correct, but should be export let gallerydata = []
On the component you then set

<Slidegallery gallerydata={images} ... />

CodePudding user response:

You could probably make do with dynamic imports but, given the form of your data, it seems easier and more straightforward to turn them into JSON and load them with fetch.

First you'd convert your galleries data to JSON files and put them in the static directory, to make them available for download. For example:

static/galleries1.json

[
    {
        "id": 0,
        "alt": "Zack and Alex arming a rocket.",
        "src": "img/gallery/rocket1.jpg"
    },
    {
        "id": 1,
        "alt": "Zack and Matt performing parachute testing.",
        "src": "img/gallery/rocket2.jpg"
    }
]

Then, you could make a gallery component like this:

<script>
    export let gallery;

    const loadGallery = (name) =>
        fetch(`/galleries/${gallery}.json`)
            .then((res) => {
                if (!res.ok) throw new Error('Fetch error');
                return res;
            })
            .then((res) => res.json());

    $: imagesPromise = gallery && loadGallery(gallery);
</script>

{#if imagesPromise}
    {#await imagesPromise then images}
        <pre>{JSON.stringify(images, null, 2)}</pre>
    {:catch err}
        <pre>{err}</pre>
    {/await}
{/if}

If you really want your galleries data to be some JavaScript, you could pass dynamic imports to your components like this:

<SlideGallery gallery={import('../data/rocketgallery.js')} ... />

Your component would then receive a promise that would resolve to the JS module. You could use them like this, for example:

SlideGallery.svelte

<script>
    export let gallery;
</script>

{#if gallery}
    {#await gallery then imageModule}
        <pre>{JSON.stringify(imageModule.images, null, 2)}</pre>
    {:catch err}
        <pre>{err}</pre>
    {/await}
{/if}

Notice that, for this to work, you need to pass static strings (i.e. not strings that are constructed with code or some string in a variable) to your dynamic imports, because otherwise the bundler won't "see" them.

// works because the bundler sees the full URL
import('../data/gallery.js')

// doesn't work because the bundler doesn't see the URL hidden
// in the dynamic string, and so the import won't be rewritten 
// to what it'll really be in your bundled app
import('../data/'   'gallery.js')

Or alternatively, you could put raw .js files in the static, so that you can know their actual runtime URLs.

  • Related