Visualize and update products with Alpine.js
Tags: alpinejs, javascript, webdev, tutorial
Published: 2023-12-18 17:00:00

> _The texts in this article were generated in parts by OpenAI's [ChatGPT](https://openai.com/blog/chatgpt/) and corrected and revised by us._

As a starting point for our demonstration of product data visualization and conversion, we use the following simplified data structure that contains important product information such as name, price, and currency:

```json
[
  {
    "name": "Arctis 1 Wireless",
    "price": {
      "value": 99.99,
      "currency": "USD"
    }
  }
]
```

Each product is stored as an object in the list and contains the `name` and `price` fields. The `price` key in turn contains an object with the price information.

## Obtain and visualize data

To be able to display the data in the frontend, we first need a way to retrieve it. For this, we use a fictitious API in our example, from which we obtain the data structure using the `getOffers()` function and store it in the `offers` object. This is done, as usual, in a specially created context within Alpine, here called `utility`.

> If you want to learn more about how to include Alpine in your environment, we recommend our post: [Including Alpine.js in a production environment](/en/blog/alpinejs/alpine-in-a-production-environment/)

```js
document.addEventListener("alpine:init", () => {
  Alpine.data("utility", () => ({
    offers: [],
    async getOffers() {
      const response = await (
        await fetch("https://steelseries.com/api/offers")
      ).json();
      this.offers = response.data;
    },
  }));
});
```

To visualize the data in the frontend, we can then use the following HTML code:

```html
<div class="offers" x-data="utility" x-init="getOffers">
  <template x-for="offer in offers">
    <article class="offer">
      <div class="offer-title" x-text="offer.name"></div>
      <div
        class="offer-price"
        x-text="`${offer.price.value} ${offer.price.currency}`"
      ></div>
    </article>
  </template>
</div>
```

## Obtain exchange rate and update prices

To be able to display the current product price in Euro, we obtain current conversion rates via an API from [exchangerate.host](https://exchangerate.host/#/). The function `getConversion()` then stores the current rate in the key `conversion`. If the API unexpectedly returns an incorrect response, we use the initial object in the key as a reference.

```js
document.addEventListener("alpine:init", () => {
  Alpine.data("utility", () => ({
    conversion: { rate: 1, currency: "USD" },
    offers: [],
    async getConversion() {
      const rate = await (
        await fetch(`https://api.exchangerate.host/convert?from=USD&to=EUR`)
      ).json();
      if (!rate.success) return;
      this.conversion = { rate: rate.result, currency: rate.query.to };
    },
    async getOffers() {
      const response = await (
        await fetch("https://steelseries.com/api/offers")
      ).json();
      await this.getConversion();
      this.offers = response.data;
    },
    setPrice() {
      const price = (this.offer.price.value * this.conversion.rate).toFixed(2);
      return `${price} ${this.conversion.currency}`;
    },
  }));
});
```

The function `setPrice()` returns the updated price and replaces the interpolated string from the previous HTML code.

```html
<div class="offers" x-data="utility" x-init="getOffers">
  <template x-for="offer in offers">
    <article class="offer">
      <div class="offer-title" x-text="offer.name"></div>
      <div class="offer-price" x-text="setPrice"></div>
    </article>
  </template>
</div>
```

Thus, we can obtain and visualize product information with current prices via Alpine. Since this is only a simple demonstration, the next step could be to extend this code with loading and fallback states that make the experience clearer and more pleasant for users in the frontend.

---

## TL;DR

Alpine is used to obtain an array of product data, the prices of which are then converted into euros using an external API in order to visualize this data as a list in the frontend.