> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aftersell.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Eventi

> Tutti gli eventi dell'SDK di Aftersell Cart: quando si attiva ciascuno, cosa ti passa, a cosa serve e gli errori che causano loop infiniti.

Gli eventi ti permettono di eseguire codice **quando succede qualcosa** nel carrello. Vivono sotto `window.aftersell.cart.events`.

La sottoscrizione è una chiamata di set-up, quindi è sicura in cima al tuo script, senza bisogno di aspettare `ready()`.

<div id="available-events">
  ## Eventi disponibili
</div>

| Evento                                        | Payload                                               | Si attiva quando                                             |
| --------------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------ |
| [`cart_loaded`](#cart_loaded)                 | [`AftersellCart`](/it/aftersell/cart/sdk-cart-object) | Il carrello si carica, una volta per pagina.                 |
| [`cart_updated`](#cart_updated)               | [`AftersellCart`](/it/aftersell/cart/sdk-cart-object) | Il contenuto del carrello cambia, dopo il primo caricamento. |
| [`item_added`](#item_added)                   | `{ item }`                                            | Una nuova riga appare nel carrello.                          |
| [`item_removed`](#item_removed)               | `{ item }`                                            | Una riga scompare dal carrello.                              |
| [`cart_opened`](#cart_opened-and-cart_closed) | Nessuno                                               | Il drawer si apre.                                           |
| [`cart_closed`](#cart_opened-and-cart_closed) | Nessuno                                               | Il drawer si chiude.                                         |
| [`checkout`](#checkout)                       | Nessuno                                               | Viene cliccato il pulsante di checkout.                      |

<div id="subscribing">
  ## Sottoscrizione
</div>

`events.on(event, handler)` registra un handler e **restituisce una funzione che ne annulla la sottoscrizione**:

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
const off = window.aftersell.cart.events.on('cart_updated', (state) => {
  console.log('Cart total is now', state.totalPrice);
});

// later, to stop listening:
off();
```

* `events.once(event, handler)`: si attiva una volta, poi annulla da solo la sottoscrizione.
* `events.off(event, handler)`: rimuove un handler specifico.

Un handler che genera un errore viene isolato e registrato in console; gli altri handler vengono comunque eseguiti.

***

<div id="the-two-rules">
  ## Le due regole
</div>

Quasi ogni bug legato agli eventi si riconduce a una di queste.

<div id="dont-change-the-cart-from-cart_updated-without-a-guard">
  ### Non modificare il carrello da `cart_updated` senza una guardia
</div>

Modificare il carrello dentro un handler `cart_updated` attiva di nuovo `cart_updated`. Se quell'handler modifica di nuovo il carrello, hai un loop infinito. L'acquirente vede il suo carrello impazzire mentre la pagina martella Shopify.

<Warning>
  **Non chiamare mai un'azione in modo incondizionato da `cart_updated` o `cart_loaded`.** Proteggila con un controllo sullo stato che stai per creare, così il secondo passaggio non fa nulla.
</Warning>

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// ❌ Loops forever: every add triggers an update, which triggers another add.
window.aftersell.cart.events.on('cart_updated', (state) => {
  window.aftersell.cart.actions.addItem(GIFT_VARIANT_ID, 1);
});

// ✅ Guarded: once the gift is present, the condition is false and it stops.
window.aftersell.cart.events.on('cart_updated', (state) => {
  const hasGift = state.items.some((line) => line.variantId === GIFT_VARIANT_ID);
  if (state.totalPrice >= 5000 && !hasGift) {
    window.aftersell.cart.actions.addItem(GIFT_VARIANT_ID, 1);
  }
});
```

Il carrello ti offre una rete di sicurezza: un aggiornamento che produce un carrello **identico** non emette nulla, quindi un refetch che non cambia nulla non riavvia il ciclo. Questo ti protegge dai loop no-op accidentali. **Non** ti protegge da un handler che modifica realmente il carrello ogni volta.

<div id="treat-the-payload-as-read-only">
  ### Tratta il payload come di sola lettura
</div>

Ogni handler di uno stesso evento riceve lo *stesso* oggetto. Modificarlo cambia ciò che vedono gli handler successivi al tuo, inclusi quelli appartenenti ad altre app dello store.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// ❌ Corrupts the payload for every later handler.
window.aftersell.cart.events.on('cart_updated', (state) => {
  state.items = state.items.filter((line) => line.finalLinePrice > 0);
});

// ✅ Copy first.
window.aftersell.cart.events.on('cart_updated', (state) => {
  const paidItems = state.items.filter((line) => line.finalLinePrice > 0);
});
```

Per modificare davvero il carrello, usa un'[azione](/it/aftersell/cart/sdk-actions). Per cambiare come vengono renderizzate le righe, usa [`registerLineTransform`](/it/aftersell/cart/sdk-hooks#registerlinetransform).

***

<div id="cart_loaded">
  ## cart\_loaded
</div>

Si attiva **una volta**, quando il carrello si carica per la prima volta sulla pagina. Il payload è l'[oggetto cart](/it/aftersell/cart/sdk-cart-object) completo.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.events.on('cart_loaded', (state) => {
  console.log('Page loaded with', state.itemCount, 'items');
});
```

**Usalo per:** qualsiasi cosa debba essere eseguita sullo stato iniziale del carrello, come riconciliare un omaggio, inizializzare un widget o segnalare il contenuto del carrello alle analytics al caricamento della pagina.

**`cart_loaded` viene riprodotto per i sottoscrittori tardivi.** Se ti sottoscrivi dopo che il carrello si è già caricato, il tuo handler viene chiamato immediatamente con il carrello corrente. L'ordine di sottoscrizione non conta mai, quindi non devi preoccuparti se il tuo script ha battuto il carrello sul tempo.

<Tip>
  La logica che deve essere corretta sia al caricamento della pagina sia a ogni modifica successiva dovrebbe sottoscriversi **sia** a `cart_loaded` **sia** a `cart_updated` con la stessa funzione. È il pattern standard per "mantieni X sincronizzato con il carrello".
</Tip>

<div id="cart_updated">
  ## cart\_updated
</div>

Si attiva ogni volta che il contenuto del carrello cambia **dopo** il primo caricamento, sia dal drawer, sia dalle tue azioni, sia dal tema, sia da un'altra app. Il payload è l'[oggetto cart](/it/aftersell/cart/sdk-cart-object) completo.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.events.on('cart_updated', (state) => {
  document.querySelector('#my-total').textContent =
    window.aftersell.cart.actions.formatMoney(state.totalPrice);
});
```

**Usalo per:** mantenere sincronizzato qualcosa al di fuori del carrello, come un totale personalizzato, una barra di avanzamento, un badge nell'header o un evento di analytics a ogni modifica.

Un aggiornamento che produce un carrello identico non emette nulla. Riaprire il drawer, tornare sulla scheda o un refetch che restituisce lo stesso contenuto non lo attiveranno.

<Warning>
  Rileggi [le due regole](#the-two-rules) prima di chiamare un'azione qui dentro.
</Warning>

<div id="item_added">
  ## item\_added
</div>

Si attiva quando una **nuova riga** appare nel carrello. Il payload è `{ item }`, dove `item` è la [riga del carrello](/it/aftersell/cart/sdk-cart-object#cart-lines).

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.events.on('item_added', (payload) => {
  myAnalytics.track('Added to cart', {
    id: payload.item.variantId,
    title: payload.item.title,
    quantity: payload.item.quantity,
  });
});
```

**Usalo per:** il tracciamento dell'add-to-cart in uno strumento di analytics di terze parti. È l'uso più comune in assoluto dell'SDK. Vedi [tracciare l'add-to-cart](/it/aftersell/cart/sdk-use-case-analytics).

Due cose da sapere su come viene derivato:

<Warning>
  **Un cambio di quantità non è un'aggiunta.** Il carrello ricava aggiunte e rimozioni facendo il diff delle *righe*, non delle quantità. Un acquirente che porta una riga da 1 a 3 attiva `cart_updated`, non `item_added`. Se devi intercettare anche gli aumenti di quantità, confronta con lo stato precedente in un handler `cart_updated`.
</Warning>

Inoltre non si attiva per gli articoli che erano già nel carrello al caricamento della pagina; quelli arrivano tramite `cart_loaded`. Aggiungere più prodotti distinti in una volta attiva l'evento una volta per riga.

<div id="item_removed">
  ## item\_removed
</div>

Si attiva quando una riga scompare dal carrello. Il payload è `{ item }`, la riga com'era subito prima di sparire, così puoi ancora leggerne `key`, `variantId` e `title`.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.events.on('item_removed', (payload) => {
  console.log('Removed', payload.item.title);
});
```

**Usalo per:** annullare qualcosa che hai fatto all'aggiunta, come cancellare un flag, mostrare di nuovo un'offerta che l'acquirente ha rifiutato o segnalare le rimozioni alle analytics.

Stessa avvertenza di `item_added`: abbassare una quantità senza arrivare a zero non è una rimozione.

<div id="cart_opened-and-cart_closed">
  ## cart\_opened e cart\_closed
</div>

Si attivano quando il drawer si apre e si chiude. Nessun payload.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.events.on('cart_opened', () => {
  myAnalytics.track('Cart viewed');
});

window.aftersell.cart.events.on('cart_closed', () => {
  document.body.classList.remove('cart-is-open');
});
```

**Usali per:** tracciamento delle visualizzazioni, mettere in pausa un video o un carosello dietro il drawer, attivare/disattivare una classe sulla pagina.

Nessuno dei due si attiva al caricamento iniziale della pagina, solo a un'apertura o chiusura effettiva.

<div id="checkout">
  ## checkout
</div>

Si attiva quando l'acquirente clicca il pulsante di checkout, immediatamente prima che il browser navighi. Nessun payload.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.events.on('checkout', () => {
  myAnalytics.track('Checkout started');
});
```

**Usalo per:** il tracciamento dell'intento di checkout.

<Warning>
  **Non puoi annullare il checkout da questo handler.** L'evento è una notifica, non un gate; la navigazione avviene indipendentemente da ciò che fa il tuo codice. Mantieni l'handler veloce e sincrono: un `await` o una chiamata di rete lenta potrebbero non terminare prima che la pagina venga scaricata. Usa [`navigator.sendBeacon`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon) per qualsiasi cosa tu debba inviare in modo affidabile.
</Warning>

***

<div id="listening-from-outside-the-sdk">
  ## Ascoltare dall'esterno dell'SDK
</div>

Ogni evento viene anche inviato come `CustomEvent` DOM su `window`, quindi puoi ascoltare senza toccare `window.aftersell.cart`. È utile da un file del tema, da un'app di terze parti o da uno script che si carica indipendentemente dal carrello.

| Evento del bus | Evento DOM                    |
| -------------- | ----------------------------- |
| `cart_loaded`  | `aftersell:cart:cart-loaded`  |
| `cart_updated` | `aftersell:cart:cart-updated` |
| `item_added`   | `aftersell:cart:item-added`   |
| `item_removed` | `aftersell:cart:item-removed` |
| `cart_opened`  | `aftersell:cart:cart-opened`  |
| `cart_closed`  | `aftersell:cart:cart-closed`  |
| `checkout`     | `aftersell:cart:checkout`     |

Attenzione alla nomenclatura: il bus usa lo `snake_case`, gli eventi DOM usano il `kebab-case` dietro un prefisso `aftersell:cart:`.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.addEventListener('aftersell:cart:cart-updated', (event) => {
  console.log('Cart total is now', event.detail.totalPrice);
});
```

Il payload arriva su `event.detail` e corrisponde all'[oggetto cart](/it/aftersell/cart/sdk-cart-object). Gli eventi vengono inviati su `window`, quindi un listener ovunque sulla pagina li riceve. Il carrello viene renderizzato in uno shadow root, ma il confine dello shadow non è mai nel percorso dell'evento. Ogni invio clona il payload, quindi un listener che modifica `event.detail` non può influenzare nessun altro, e un listener che genera un errore non può interferire con l'SDK.

<Warning>
  **`cart-loaded` non viene riprodotto sul DOM.** Il bus riproduce `cart_loaded` per i sottoscrittori tardivi, ma quel percorso bypassa l'invio DOM, quindi `window.addEventListener('aftersell:cart:cart-loaded')` registrato dopo che il carrello si è già caricato non si attiverà mai. Se l'ordine di caricamento del tuo script non è garantito, usa `window.aftersell.cart.events.on('cart_loaded', …)`, che invece riproduce, oppure ascolta anche `aftersell:cart:cart-updated`.
</Warning>

<div id="shopify-standard-cart-events">
  ### Eventi standard del carrello di Shopify
</div>

Separatamente, il carrello pubblica gli [eventi standard del carrello](https://shopify.dev/docs/storefronts/themes/best-practices/standard-events) di Shopify su `document` ogni volta che modifica il carrello, così il codice del tema e le altre app possono reagire alle mutazioni di Aftersell nello stesso modo in cui reagiscono a quelle del tema:

| Evento                         | Payload sull'istanza dell'evento                                                 |
| ------------------------------ | -------------------------------------------------------------------------------- |
| `shopify:cart:lines-update`    | `action: 'add' \| 'update' \| 'remove'`, `context: 'cart' \| 'product'`, `lines` |
| `shopify:cart:note-update`     | `context: 'cart'`, `note`                                                        |
| `shopify:cart:discount-update` | `discountCodes: [{ code }]`                                                      |

<Warning>
  **Il payload non è su `event.detail`.** `detail` contiene solo `{ source: 'aftersell' }` — il tag che il carrello usa per ignorare i propri eventi invece di andare in loop. Tutto ciò che è nella tabella sopra è assegnato direttamente sull'oggetto evento, quindi leggi `event.action`, non `event.detail.action`.
</Warning>

Ogni evento porta anche una `promise` che Aftersell risolve quando la scrittura sottostante va a buon fine, in linea con lo standard di Shopify — attendila con await, non risolverla tu. Questi eventi vengono inviati su `document` e fanno bubbling, quindi anche un listener su `window` li riceve.

<div id="where-to-go-next">
  ## Dove andare adesso
</div>

* **[Oggetto cart](/it/aftersell/cart/sdk-cart-object)**: la struttura completa dei payload qui sopra.
* **[Azioni](/it/aftersell/cart/sdk-actions)**: come modificare il carrello da un handler.
* **[Hook](/it/aftersell/cart/sdk-hooks)**: per cambiare come il carrello viene renderizzato, invece di reagire ad esso.
* **[Casi d'uso](/it/aftersell/cart/sdk-use-cases)**: tracciamento analytics, omaggi e altri esempi completi.
