Get meta data via Ajax

Hello,

Here is my origal message posted on Discord

Hello, newbie question …
I making a website with a lot of images and they are store by differents fields.
I have a description field for them, and I would like to show the content of the description field in a lightbox when I click on the image.
But I can’t store the content of the field in the data attribute because my field is an textarea.

So I don’t know how to do this.

I thought, I can do something like I put the id of the image in data attribute, and on click I check this ID and I make a query for find my description field associate and show it.
But I can’t find how do the query (I would know how do it with mysql).

I would’nt like make hidden div with content, and show them on click, because, it seems ugly. I could have 30 hidden div in one page.

Do you have any suggestion or council ?

Thanks

Sonja replied :

If you have the image id in your data attribute, you can use that together with a route that listens to this id. Based on this id you can find the image and return the description

But I’m not really confortable with it as beginner and I’ll need some help.
I have difficulties to understand how all it work even with the documentations :confused:

Thanks you !

Ok, let’s say you loop through all the images of a page like this:

<?php foreach ($page->images() as $image): ?>
  <img src="<?= $image->url() ?>" alt="" class="lightbox" data-image="<?= $image->id()?>">
<?php endforeach ?>

We assign the image’s id (= path to the image) as data-image attribute.

In /site/config/config.php within the return array, we add a route:

<?php
return [
    // … other settings
    // example route
    'routes' => [
        [
            'pattern' => 'meta/(:all)/(:any)',
            'action'  => function($pageId, $fileName) {
                // try to find the page by id and the file in the page
                if (($page = page($pageId)) && $file = $page->file($fileName)) {
                    // create and return a data array with the file data we want
                    return [
                        'description' => $file->description()->or('some fallback text')->kt(),
                    ];
                }
            }
        ]
    ],
];

Then in your template (or a script), you add a piece of JavaScript that listens to click events and fetches the data from the route:

<script>
const elements = document.querySelectorAll('.lightbox');
elements.forEach((element) => {
  element.addEventListener('click', async() => {
    // get file Id from data-image attribute
    let fileId = element.getAttribute('data-image');
    // create the url in the format we need for the route
    let url    = `http://${window.location.hostname}/meta/${fileId}`;

    // fetch request to route
    try {
      const response        = await fetch(url);
      const { description } = await response.json();
      // do something with the data
      console.log(description);

    } catch (error) {
      console.log('Fetch error: ', error);
    }

  });
});
</script>
2 Likes

Hello,

Thanks for this reply.

I tried the code but, there is something wrong.

I have got an error

Fetch error:  SyntaxError: Unexpected token � in JSON at position 0

I searched what can be the error but I don’t know.
I suppose that the error is between JSON and my file format, but i don’t know.

When exactly does this error happen? Is there a stack trace? I tested the code in a fresh Starterkit before posting here and for me it works. Did you make any changes?

I got the error when I click on image.
I changed the file field name of the config.php code for call the good one.
I tried to rename it “description” but the error is still here.

That’s all.

On click, I have a first element ‘sinfaro.jpg’ that is loading. The first one is a 307 Tempory Redirect state code.
Than a second than I show in following screenshot.

Screen for network tab.


In response tab, I have this message :

No response data available for this query

Hm, the request goes to http://sinfaro.test/meta/sinfaro.jpg, so it won’t work, because the route expects a url with a path to the page + filename. Could you post the part of the template code that contains the data attribute? Or is the file not inside a page?

There is my code of my home page, that show several images.

foreach ($sections as $section):
  $img = $section->sectionimg()->toFile();
...
  <img class="lightbox" src="<?= $img->url() ?>" data-image="<?= $img->id() ?>" data-test="<?= $img->description() ?>">
...
<?php endforeach ?>

I don’t have a specific page for each image.

And the value of the data-image attribute is only a filename? That’s why I was asking if the images belong to a page. Or where are the images stored? In any case, the URL and the route do not match and that is the problem.

Yes the value of the data-image attribute is only a filename.

I can find my image in the content folder, and in the media > site folder.
I changed the upload folder because, I wanted offer the possibility to reuse image already upload in the site everytime.

Ok, so you are uploading to directly to the content folder and therefore your images are files of the $site object. Then we have to fix the route like this:

<?php
return [
    // … other settings
    // example route
    'routes' => [
        [
            'pattern' => 'meta/(:any)',
            'action'  => function($fileName) {
                // try to find the page by id and the file in the page
                if ($file = site()->file($fileName)) {
                    // create and return a data array with the file data we want
                    return [
                        'description' => $file->description()->or('some fallback text')->kt(),
                    ];
                }
            }
        ]
    ],
];
1 Like

That is working !

You are amazing, thank you so much for you time !

Thank for you patience, and sorry for my english and my misunderstandings.

Have a good night :slight_smile: