# Goal bar events

> The andor:goal:tier-change event and the widget events the goal bar dispatches, with payloads and listener examples, plus its data attributes and states.

Source: https://backtrackhq.com/docs/widgets/goal-bar/events/

This page is for theme developers. The live goal bar,
`<andor-goal data-andor-widget="goal">`, sends the shared widget events
and `andor:goal:tier-change` when the cart reaches a different step.

All events are `CustomEvent`s that bubble, so you can listen on
`document`.

## Events

| Event | Sent on | When |
|---|---|---|
| `andor:widget:mount` | the bar | the first pass that sees it |
| `andor:widget:unmount` | the bar and `document` | the first pass after it left the page |
| `andor:display:change` | the bar | its state changed, for example it hid |
| `andor:goal:tier-change` | the bar | the number of steps reached changed after a cart change |

Rules worth knowing:

- **No event on first print.** The first print stores the step count
  silently.
- **One event per bar.** Each bar on the page (for example the cart
  page bar and the cart drawer copy) fires its own event.
- **A sample bar sends nothing.** The theme editor's sample bar carries
  no `data-andor-widget`.

## Payloads

`andor:widget:mount`, `andor:widget:unmount` and
`andor:display:change` carry `event.detail.resource`:

| Field | Value for this widget |
|---|---|
| `widgetType` | `"goal"` |
| `widgetId` | the block id, or `"pasted"` for a pasted tag |
| `productId` | `null` (the bar carries no product id) |

`andor:display:change` adds `previous` and `current` state objects. The
field to watch on a bar is `visible`. See the full payload on
[Events](https://backtrackhq.com/docs/developers/events/).

`andor:goal:tier-change` carries `event.detail`:

| Field | Type | Meaning |
|---|---|---|
| `previousTier` | number | steps reached before: `0` none, `1` the first, and so on |
| `currentTier` | number | steps reached now |
| `cartTotalCents` | number | the subtotal the bar measured, in cents |

Example: a bar with steps at $50 and $100. The cart goes from $40 to $60.
The event has `previousTier: 0`, `currentTier: 1` and
`cartTotalCents: 6000`.

## Examples

Log when the cart reaches a new step:

```js
document.addEventListener("andor:goal:tier-change", (event) => {
  const { previousTier, currentTier, cartTotalCents } = event.detail;
  if (currentTier > previousTier) {
    console.log("goal step reached", currentTier, "at", cartTotalCents);
  }
});
```

Tell the page bar and the drawer copy apart with `event.target`:

```js
document.addEventListener("andor:goal:tier-change", (event) => {
  const inDrawer = event.target.hasAttribute("data-andor-goal-clone");
  console.log(inDrawer ? "drawer bar" : "page bar", event.detail.currentTier);
});
```

### Reading the bar's position

> **Caution:** This is an internal signal. Its shape can change without
> notice. Prefer `andor:goal:tier-change` when it is enough.

A bar keeps its position on the element as `bar.andorGoalAt`:
`{ cents, next }`, the subtotal it measured and the next milestone
(empty once the top step is reached). An `andor-goal-at` event fires on
`document` when `next` moves to another milestone. Read it, never write
it:

```js
document.addEventListener("andor-goal-at", () => {
  const bar = document.querySelector("andor-goal[data-andor-widget]");
  const at = bar && bar.andorGoalAt;
  if (at && at.next) console.log("next goal at", at.next.cents);
});
```

## Events the widget listens for

- `shopify:cart:lines-update`: the cart changed. The bar reads it again.
- `shopify:cart:view`: the cart drawer opened. The drawer copy draws.
- `shopify:section:load`: the theme editor re-rendered a section.

The drawer copy needs a theme that sends `shopify:cart:view`. Horizon
4.0 and Dawn 15.5 and later do.

## Data attributes and states

| Attribute or class | On | Meaning |
|---|---|---|
| `data-andor-goal-reached` | `.andor-goal__step` | this step is reached |
| `.andor-goal--vertical` | host | the stacked layout |
| `data-andor-skeleton` | host | not printed yet: shimmers, sized |
| `data-andor-goal-settled` | host | printed from a real cart. The fill slides |
| `data-andor-kept="note"` | host | gone mid-visit: one line says why |
| `data-andor-goal-clone` | host | the copy in the cart drawer |
| `data-andor-icon` | step or icon | `off`, `ship` or `gift` |
| `data-drawer="only"` | pasted tag | feeds the drawer only |
| `data-icons="false"` | pasted tag | no reward icons on this bar |
| `data-icon-position` | pasted tag | `label`: icons beside the labels |

The next step has no attribute of its own. It is the first step without
`data-andor-goal-reached`:

```css
.andor-goal__step:first-child:not([data-andor-goal-reached]),
[data-andor-goal-reached] + .andor-goal__step:not([data-andor-goal-reached]) {
  font-weight: 600;
}
```

For the attributes every widget shares, like `data-andor-state` and
`data-andor-progress`, see
[Data attributes and states](https://backtrackhq.com/docs/developers/data-attributes/).
