# Data loading

Source: https://signy.dev/examples/data-loading/

A table that loads, reloads and fails on purpose.

A resource fetches books from a pretend API that answers after 600ms. Its source reads the genre and the failure switch, so changing either fetches again. The table shows the last result while the next one loads.

## Preview

[Open the page on its own](https://signy.dev/examples/data-loading/demo/index.html.md)

## Code

Save it as an `.html` file and open it in a browser. It loads Signy and Iris CSS from the CDN, so there is nothing to install or build.

**Show the full page**

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="color-scheme" content="light dark">
    <title>Data loading - Signy example</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/iriscss@1/dist/iris.min.css">
    <script src="https://cdn.jsdelivr.net/npm/signy@1/dist/signy.global.min.js"></script>
  </head>
  <body>
    <main class="container" id="app"></main>

    <script>
      const { Component, Signal, application, html, resource, For, Show } = Signy;

      // A pretend API: answers after 600ms, and fails when asked to
      const BOOKS = [
        { id: 1, title: "Kindred", author: "Octavia E. Butler", genre: "fiction" },
        { id: 2, title: "The Left Hand of Darkness", author: "Ursula K. Le Guin", genre: "fiction" },
        { id: 3, title: "Hidden Figures", author: "Margot Lee Shetterly", genre: "history" },
        { id: 4, title: "The Innovators", author: "Walter Isaacson", genre: "history" },
        { id: 5, title: "Gödel, Escher, Bach", author: "Douglas Hofstadter", genre: "science" },
        { id: 6, title: "The Selfish Gene", author: "Richard Dawkins", genre: "science" },
      ];

      function fetchBooks({ genre, fail }) {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            if (fail) reject(new Error("The server did not answer. Try again."));
            else resolve(BOOKS.filter((book) => genre === "all" || book.genre === genre));
          }, 600);
        });
      }

      class Library extends Component {
        genre = new Signal("all");
        fail = new Signal(false);
        // The source reads both signals, so changing either fetches again
        books = resource(() => ({ genre: this.genre.value, fail: this.fail.value }), fetchBooks);

        render() {
          return html`
            <h1>Library</h1>
            <form class="cluster" onSubmit=${(e) => e.preventDefault()}>
              <label>
                Genre
                <select onChange=${(e) => (this.genre.value = e.currentTarget.value)}>
                  <option value="all">All</option>
                  <option value="fiction">Fiction</option>
                  <option value="history">History</option>
                  <option value="science">Science</option>
                </select>
              </label>
              <label>
                <input type="checkbox" role="switch" onChange=${(e) => (this.fail.value = e.currentTarget.checked)} />
                Make the server fail
              </label>
              <button type="button" class="secondary outlined" onClick=${() => this.books.refetch()}>Reload</button>
            </form>

            ${Show({
              when: () => this.books.error,
              children: (error) => html`<p class="alert danger" role="alert">${error.message}</p>`,
            })}

            <div aria-busy=${() => String(this.books.loading)}>
              <table class="striped">
                <thead>
                  <tr><th scope="col">Title</th><th scope="col">Author</th><th scope="col">Genre</th></tr>
                </thead>
                <tbody>
                  ${For({
                    each: () => this.books.value ?? [],
                    keyBy: "id",
                    children: (book) => html`
                      <tr><td>${book.title}</td><td>${book.author}</td><td>${book.genre}</td></tr>
                    `,
                  })}
                </tbody>
              </table>
            </div>
          `;
        }
      }

      application(Library).mount("#app");
    </script>
  </body>
</html>

```

## What it uses

- [Resource](https://signy.dev/documentation/1/reactivity/resource/index.html.md) with a source, `loading`, `error` and `refetch()`
- [Show](https://signy.dev/documentation/1/templates/show/index.html.md) for the error, and [For](https://signy.dev/documentation/1/templates/for-and-index/index.html.md) for the rows
