DEV Community

Brewhouse Digital
Brewhouse Digital

Posted on

Advanced 11ty: Using Objects in your UI

In this tutorial, we will be writing an async / await call and then returning its response (an object) to the UI for further use.

Specifically, we'll be reading EXIF data from a photo in our images folder, but you'll be able to swap out our asynchronous call for any other asynchronous call you have, such as a fetch request, or another NPM package that you're using.

To begin, we're going to start with an 11ty filter. This is because filters can be chained together, we we'll need to do that in order to extract all of the object data on our front-end. I'll be using the Nunjucks syntax, but you'll be able to switch between Liquid or Handlebars fairly easily.

Inside our eleventy.js file, lets create our new filter:

eleventyConfig.addNunjucksAsyncFilter("getExifData", async function(image, callback) {
   // Coming soon
}
Enter fullscreen mode Exit fullscreen mode

Starting from the top line, the built in 11ty method addNunjucksAsyncFilter will create a promise for us that won't be resolved until we say so, using the callback parameter at the end. I'll get into more detail on that later.

After the method, we give our filter a name. In this case, "getExifData". This is how we'll call the filter on the UI. After that, we create our async function and in our example, we want to pass an image path to our filter for the processing. The last thing you include in the parameters is the callback. This is required or the promise will never complete, and sometimes 11ty can crash if its not there.

Now what we want to do is import our NPM package. I'll be using ExifReader for this.

P.S. this is where you would swap out for your own asynchronous package / function.

npm i exifreader
Enter fullscreen mode Exit fullscreen mode

At the top of your eleventy.js file, you can call it inside your app like so:

const ExifReader = require('exifreader');
Enter fullscreen mode Exit fullscreen mode

Now that its added to our project, we can use it inside our new filter.

eleventyConfig.addNunjucksAsyncFilter("getExifData", async function(image, callback) {
   const exifData = await ExifReader.load(image);
}
Enter fullscreen mode Exit fullscreen mode

What this will do is take an image path thats supplied to the filter, run it through the NPM package, and return a gigantic object of all the EXIF data contained within the image. This particular package is asynchronous so we need to add the await parameter so that 11ty doesn't finish compiling before the promise is fulfilled.

In my case, I dont need all of the data returned from this package, so I'm going to create my own Object of just the things I want.

eleventyConfig.addNunjucksAsyncFilter("getExifData", async function(image, callback) {
   const exifData = await ExifReader.load(image);

    const extractedValues = {
        camera: exifData.Model.value,
        shutterSpeed: exifData.ExposureTime.value,
        fStop: exifData.FNumber.value,
    }
}
Enter fullscreen mode Exit fullscreen mode

Now I've simplified what data gets returned, and this will make it much easier to call on the UI side. Otherwise, I would have to drill down each of the objects and that might look messy if we're using this filter a lot. This way, it is standardized before it hits the front-end.

Now we need to resolve our promise. We do that by using the last function parameter, callback, passing null as the first value, and then our data that we want returned as the second value.

eleventyConfig.addNunjucksAsyncFilter("getExifData", async function(image, callback) {
   const exifData = await ExifReader.load(image);

    const extractedValues = {
        camera: exifData.Model.value,
        shutterSpeed: exifData.ExposureTime.value,
        fStop: exifData.FNumber.value,
    }

    callback(null, extractedValues);
}
Enter fullscreen mode Exit fullscreen mode

Now we're ready to call this on the UI side.

Inside of your front-end files (in this case I'll be using blog-post.html), we can call the filter.

{{ "images/beach/sandy-waves.jpg" | getExifData }}
Enter fullscreen mode Exit fullscreen mode

If you run this code, you'll probably see that it returns [object Object]. That means we're on the right path! Javascript doesn't let you print objects to the DOM as text, so we know that the eleventy.js filter is doing what it is supposed to do.

Now we can save this object into its own variable using a nunjucks function called set. And because we used a filter in the beginning, we can chain these together like so:

Inside your blog-post.html file change your expression syntax {{ }} to be the function syntax {% %} and call set:

{% set PhotoData = "images/beach/sandy-waves.jpg" | getExifData %}
Enter fullscreen mode Exit fullscreen mode

Now we have our object stored in a way that we can work with.

In our UI, try this out:

<h1>Camera: {{ PhotoData.camera }}</h1>
Enter fullscreen mode Exit fullscreen mode

And you should see your object data being compiled to the UI!

Completed Code

eleventyConfig.addNunjucksAsyncFilter("getExifData", async function(image, callback) {
   const exifData = await ExifReader.load(image);

    const extractedValues = {
        camera: exifData.Model.value,
        shutterSpeed: exifData.ExposureTime.value,
        fStop: exifData.FNumber.value,
    }

    callback(null, extractedValues);
}
Enter fullscreen mode Exit fullscreen mode
{% set PhotoData = "images/beach/sandy-waves.jpg" | getExifData %}

<h1>Camera: {{ PhotoData.camera }}</h1>
Enter fullscreen mode Exit fullscreen mode

This is how we can bring objects into our 11ty UI and parse them into our code. Hope you enjoyed this tutorial.

This same process will work even if you dont use an asynchronous call. Just remove all the async / await parameters and then change your addNunjucksAsyncFilter to addFilter.

Top comments (0)