Javascript Data Files

and you

Bryan Robinson

11ty Fan

Designer Who Codes

Host @ That's My Jamstack

DevRel @ Sanity.io

 

@brob

11ty Data Files

11ty Data Files

{
    "siteName": "My amazing site",
    "arrays": [
    	"Sure",
        "why",
        "not"
    ]
}

_data/settings.json

<h1>{{ settings.siteName }}</h1>
<ul>
    {% for item in settings.arrays %}
    	<li>{{ item }}</li>
    {% endfor %}
</ul>

_includes/index.njk

Me using static data file

Me using JS data file

11ty JS Data Files

11ty JS Data Files

module.exports = function() {
  return [
    "Pikachu",
    "Bulbasaur",
    "Charmander",
    "only the original",
    "151 because I'm old"
  ];
};

_data/pokemon.js

<h1>Pokemon</h1>
<ul>
    {% for pokemon in pokemon %}
    	<li>{{ pokemon }}</li>
    {% endfor %}
</ul>

_includes/index.njk

Fetch Data from an API

const fetch = require('node-fetch');

const fetchPokemon = () => {
    const promises = [];
    for (let i = 1; i <= 150; i++) {
        const url = `https://pokeapi.co/api/v2/pokemon/${i}`;
        promises.push(fetch(url).then((res) => res.json()));
    }
    return Promise.all(promises).then((results) => {
        const pokemon = results.map((result) => ({
            name: result.name,
            image: result.sprites['front_default'],
            type: result.types.map((type) => type.type.name).join(', '),
            id: result.id
        }));
        return pokemon;
    });
};

module.exports = async function() {
    return await fetchPokemon();
}

Use our API Data in a loop

<div class="container">
    <h1>Robinson's Pokedex</h1>
    <ul id="pokedex">
        {% for pokemon in pokemon %}
            <li class="card">
                <img class="card-image" src="{{ pokemon.image }}"/>
                <h2 class="card-title">{{ pokemon.id }}. {{ pokemon.name }}</h2>
                <p class="card-subtitle">Type: {{ pokemon.type }}</p>
            </li>
        {% endfor %}
    </ul>
</div>

Build Pages with our data

---
pagination: 
    data: pokemon
    size: 1
    alias: entry
permalink: "different/{{ entry.name | slug }}/index.html"
---
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Robinson's PokeDex</title>
    <link rel="stylesheet" href="/style.css">
</head>
<body>
    <div class="container">
        <h1>{{ entry.id }}. {{ entry.name }}</h1>
        <img class="card-image" src="{{ entry.image }}"/>
        <p class="card-subtitle">Type: {{ entry.type }}</p>
    </div>
</body>
</html>

More Use cases

Pull Meetups from Meetup.com

var axios   = require('axios');

module.exports = async function() {
  let url = `https://api.meetup.com/${process.env.MEETUP_URL }/events?photo-host=public&page=20&sig_id=${process.env.MEETUP_KEY}`;
  
  return axios.get(url)
      .then(function (response) {
          return response.data;
      })
      .catch(function(error) {
          console.log(error);
      });
}

Pull Meetups from Meetup.com

<ul>  
  {% for meetup in meetups %}  
  <li>
    <a href="{{ meetup.link }}">{{ meetup.name }}</a>
  </li>  
  {% endfor %}  
</ul>

Pull Meetups from Meetup.com and filter

var axios   = require('axios');

module.exports = async function() {
    let url = `https://api.meetup.com/${process.env.MEETUP_URL }/events?photo-host=public&page=40&sig_id=${process.env.MEETUP_KEY}`;
    let stringMatch = ""; // Match meetup name against a string if you need to filter
    return axios.get(url)
        .then(function (response) {
            let data = response.data;
            if (stringMatch.length > 0) {
                data = data.filter(meetup => {
                    return meetup.name.includes(stringMatch);
                });
            }
            return data;
        })
        .catch(function(error) {
            console.log(error);
        });

}

Pull Meetups from Meetup.com and filter

// /filters/lookup.js
module.exports = function(array, filterString) {
    array = array.filter(item => {
        return item.name.includes(filterString);
    });
    return array
}


// /.eleventy.js 
config.addFilter("lookup", require("./filters/lookup.js"));

// index.njk
{% assign meetupSlice = meetups | lookup: "Jamstack Toronto" | slice: "1"  %}

Posts from a CMS (Sanity, anyone?)

const BlocksToMarkdown = require('@sanity/block-content-to-markdown')
const groq = require('groq')
const client = require('../utils/sanityClient.js')
const serializers = require('../utils/serializers')
const hasToken = !!client.config().token


async function getPosts () {
  // Learn more: https://www.sanity.io/docs/data-store/how-queries-work
  const filter = groq`*[_type == "post" && defined(slug) && publishedAt < now()]`
  const projection = groq`{
    _id,
    publishedAt,
    title,
    slug,
    excerpt,
    mainImage{
      alt,
      asset
    },
    body,
    "authors": authors[].author->
  }`
  const order = `| order(publishedAt asc)`
  const query = [filter, projection, order].join(' ')
  const pages = await client.fetch(query).catch(err => console.error(err))
  const preparePosts = pages.map(generatePost)
  return preparePosts
}

module.exports = getPosts

_data/post.js

Posts from Sanity

---
layout: layouts/post
tags:
  - myPosts
pagination:
  alias: post
  data: posts
  size: 1
  addAllPagesToCollections: true
permalink: posts/{{ post.slug.current | slug }}/index.html
---


Posts from Sanity

<article>
  <h1>{{ post.title }}</h1>
  {% if post.mainImage.asset %}
    <img src="{% imageUrlFor post.mainImage.asset._ref, 400, 400 %}" alt="">
  {% endif %}
  <p>Written by {% for author in post.authors %}{{author.name}}{% endfor %}</p>
  {{ post.body | markdownify | safe }}
</article>

11ty is awesome and so are you

If you have questions, I'm on Twitter @brob

11ty JS Data Files and You

By Bryan Robinson

11ty JS Data Files and You

  • 516