> ## 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.

# Hooks

> Verander hoe de Aftersell Cart zich gedraagt: transformeer regels, verrijk ze met Storefront-data, vorm abonnementsopties en beheers add-to-cart.

Waar je met [events](/nl/aftersell/cart/sdk-events) op de winkelwagen kunt *reageren* en hem met [actions](/nl/aftersell/cart/sdk-actions) kunt *wijzigen*, veranderen **hooks** hoe de winkelwagen zelf zich gedraagt: hoe regels renderen, welke data ze dragen en wat er gebeurt bij add-to-cart.

Hooks staan onder `window.aftersell.cart.hooks`.

<Note>
  Een hook verandert wat de shopper **ziet**; een action verandert wat er **in de winkelwagen zit**. Een gratis-geschenkregel verbergen met een transform laat hem in de winkelwagen en in het totaal. Hem verwijderen met [`removeItem`](/nl/aftersell/cart/sdk-actions#removeitemkey) haalt hem er echt uit.
</Note>

<Note>
  Hooks zijn set-up-aanroepen, dus veilig om helemaal bovenaan je script te registreren, zonder te hoeven wachten op `ready()`. Registreer ze in het **Initialization**-script van je winkelwagen (zie [Aangepaste scripts](/nl/aftersell/cart/custom-scripts)).
</Note>

<div id="how-registration-works">
  ## Hoe registratie werkt
</div>

Elke hook is een `register*`-methode. Je roept hem aan met je functie; hij geeft een **deregistratiefunctie** terug die je kunt aanroepen om de jouwe te verwijderen.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
const off = window.aftersell.cart.hooks.registerSkipAddToCartRule((form) =>
  form.hasAttribute('data-skip-aftersell')
);

// later: off();
```

Registratie is **additief**, dus je functie draait naast alle andere. Dat is belangrijk omdat je script zelden het enige op de pagina is: een abonnementsapp, een bundelapp en het thema zelf kunnen zich allemaal op dezelfde hook registreren. Geen van hen kan de jouwe vervangen, en niets dat jij registreert kan stilzwijgend worden weggegooid door wat er na jou laadt.

| Hook                                                                                      | Wat het doet                                                                                                                     | Bij meerdere registraties                                     |
| ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
| [`registerLineTransform`](#registerlinetransform)                                         | Verberg of herlabel individuele regels.                                                                                          | Alle draaien, in registratievolgorde.                         |
| [`registerLineComparator`](#registerlinecomparator)                                       | Herorden de gerenderde regels.                                                                                                   | Componeren als tie-breakers.                                  |
| [`registerCartEnricher`](#registercartenricher)                                           | Voeg extra Storefront-data toe aan elke regel.                                                                                   | Alle draaien; elke `id` is zijn eigen namespace.              |
| [`registerSubscriptionOptionsTransform`](#registersubscriptionoptionstransform)           | Verberg of hernoem de selling plans van een regel.                                                                               | Alle draaien; patches worden samengevoegd per plan, per veld. |
| [`registerDefaultSubscriptionOptionSelector`](#registerdefaultsubscriptionoptionselector) | Kies welk plan is voorgeselecteerd.                                                                                              | Eerste niet-`null`-antwoord wint.                             |
| [`registerSkipAddToCartRule`](#registerskipaddtocartrule)                                 | Laat specifieke formulieren de winkelwagen omzeilen. Zie [Add-to-cart-interceptie](/nl/aftersell/cart/add-to-cart-interception). | Elke regel die `true` teruggeeft slaat over.                  |

Een hook die een fout gooit, of die geen functie is, wordt overgeslagen; de rest draait gewoon, en de winkelwagen gaat door. Eén kapotte integratie kan add-to-cart, de abonnementskiezer of de sortering niet platleggen.

De keerzijde is dat een kapotte hook van jou **stilzwijgend** faalt: er bereikt niets de browserconsole. Zie [Debuggen](/nl/aftersell/cart/sdk-overview#debugging) voor waar die fouten wel opduiken.

***

<div id="registerlinetransform">
  ## registerLineTransform
</div>

`registerLineTransform(fn)` draait voor elke winkelwagenregel voordat die rendert. Gebruik het om een regel te verbergen of te veranderen hoe hij leest, zonder aan te raken wat er daadwerkelijk in de winkelwagen van de shopper zit.

De functie ontvangt een alleen-lezen regel plus setters. Hij geeft een deregistratiefunctie terug.

| Setter                            | Effect                                                                                                                                                 |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `setHidden(bool)`                 | Verberg de regel in de drawer. Hij blijft in de winkelwagen en in het totaal.                                                                          |
| `setTitle(string)`                | Verander de weergegeven titel.                                                                                                                         |
| `setVariantTitle(string \| null)` | Verander het weergegeven variantlabel.                                                                                                                 |
| `setInternalProperties(obj)`      | Voeg alleen-render-properties samen. Wordt nooit bewaard in Shopify. Gebruikt om [bundelregels te groeperen](/nl/aftersell/cart/sdk-use-case-bundles). |

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// Hide free gift lines from the drawer. The cart total is unaffected.
const off = window.aftersell.cart.hooks.registerLineTransform((line) => {
  if (line.finalLinePrice === 0) {
    line.setHidden(true);
  }
  if (line.sellingPlan) {
    line.setVariantTitle(`Delivered ${line.sellingPlan.name.toLowerCase()}`);
  }
});

// later: off();
```

<Warning>
  Een transform verandert alleen wat er rendert. Hij kan prijs, aantal of regelidentiteit niet veranderen. Gebruik daarvoor de [actions](/nl/aftersell/cart/sdk-actions).
</Warning>

**Gebruik het voor:** gift-with-purchase- of door apps geïnjecteerde regels verbergen, abonnementsregels herlabelen, afgeprijsde artikelen taggen, bundelcomponenten verbergen die de shopper niet afzonderlijk zou moeten beheren.

`setInternalProperties` is de setter achter bundelgroepering: door de canonieke bundelproperties op elke regel te stempelen laat je de losse winkelwagenregels van een externe app als één artikel renderen. Zie [Bundelregels van een andere app groeperen](/nl/aftersell/cart/sdk-use-case-bundles).

<div id="registerlinecomparator">
  ## registerLineComparator
</div>

Een comparator in dezelfde vorm die `Array.prototype.sort` verwacht. Hij draait na verbergen en hernoemen, dus hij ziet de getransformeerde regels.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// Subscriptions first, then everything else.
window.aftersell.cart.hooks.registerLineComparator((lineA, lineB) => {
  return (lineB.sellingPlan ? 1 : 0) - (lineA.sellingPlan ? 1 : 0);
});
```

Comparators **componeren als tie-breakers**: de eerste die een waarde anders dan nul teruggeeft beslist dat paar, en de rest wordt alleen geraadpleegd bij gelijke stand. Geef `0` terug voor paren waar je geen mening over hebt. Dat geeft de beslissing door aan de volgende comparator in plaats van er een volgorde aan op te leggen.

**Gebruik het voor:** abonnementen of artikelen met hoge waarde naar boven laten drijven, gratis geschenken en add-ons naar beneden laten zakken, een gesponsord product bovenaan houden.

<div id="registercartenricher">
  ## registerCartEnricher
</div>

`registerCartEnricher(registration)` haalt extra product- of variantdata op uit de Shopify Storefront API en koppelt die aan elke bijpassende winkelwagenregel op `line.metadata[id]`. Gebruik het om metafields, tags of wat de Storefront API verder ook blootlegt naar boven te halen, zonder dat er een codewijziging van Aftersell nodig is.

| Veld       | Type                              | Beschrijving                                                                                                                               |
| ---------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `id`       | `string`                          | Namespace voor het resultaat; het landt op `line.metadata[id]`. Moet uniek zijn; een tweede registratie met dezelfde `id` wordt genegeerd. |
| `onType`   | `'Product'` of `'ProductVariant'` | Op welke node het fragment zich richt. Ook de join-sleutel (product-ID vs. variant-ID).                                                    |
| `fragment` | `string`                          | Een GraphQL-veldselectie (zonder buitenste accolades) die in de Storefront-query wordt gesplitst. Accolades moeten in balans zijn.         |

Geeft een **deregistratiefunctie** terug.

Telkens wanneer de winkelwagen laadt of verandert, haalt Aftersell je fragment op voor elk product of elke variant in de winkelwagen en koppelt het resultaat. De fetch is niet-blokkerend: de winkelwagen rendert direct en stuurt `cart_updated` opnieuw uit zodra de data landt. Een traag of falend fragment vertraagt of breekt de winkelwagen nooit.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.hooks.registerCartEnricher({
  id: 'pricing',
  onType: 'ProductVariant',
  fragment: `
    anchorPrice: metafield(namespace: "custom", key: "anchor_price") { value }
    subscriberPrice: metafield(namespace: "custom", key: "subscriber_price") { value }
  `,
});

// Read it once the data arrives.
window.aftersell.cart.events.on('cart_updated', (state) => {
  state.items.forEach((line) => {
    const anchor = line.metadata.pricing?.anchorPrice;
    if (anchor) console.log(line.title, 'anchor price', anchor.value);
  });
});
```

Omdat verrijking asynchroon is, moet je de leesactie altijd beveiligen, aangezien `line.metadata.pricing` `undefined` is totdat de eerste fetch resolvet, en `metadata` zelf standaard `{}` is.

**Gebruik het voor:** een metafield op elke regel binnenhalen (een leveringsschatting, een ingrediëntenlijst, een "wordt apart verzonden"-vlag, een loyaliteitsvermenigvuldiger) en dat renderen via een [Custom code-blok](/nl/aftersell/cart/custom-code-blocks). Zie [metafield-data tonen op winkelwagenregels](/nl/aftersell/cart/sdk-use-case-metafields).

<Note>
  Meerdere enrichers bestaan probleemloos naast elkaar, aangezien elke `id` zijn eigen namespace is en hun data dus nooit botst.
</Note>

<Warning>
  Verrijkte waarden komen ongewijzigd terug van de Storefront API en worden **niet** gesaneerd. Render ze als tekst, niet als rauwe HTML.
</Warning>

<div id="registersubscriptionoptionstransform">
  ## registerSubscriptionOptionsTransform
</div>

Verberg of hernoem de selling plans die op een regel worden aangeboden. Je functie ontvangt alleen-lezen opties plus setters, en geeft niets terug.

| Setter            | Effect                            |
| ----------------- | --------------------------------- |
| `setHidden(bool)` | Verberg het plan in de kiezer.    |
| `setName(string)` | Verander de weergegeven plannaam. |

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.hooks.registerSubscriptionOptionsTransform((options, context) => {
  // context: { productId, variantId }
  options.forEach((option) => {
    if (option.discountPercent === 0) option.setHidden(true);
    option.setName(option.name.replace('Every ', ''));
  });
});
```

**Setters, geen teruggegeven lijst, zodat meerdere scripts kunnen samenleven.** Als deze hook een array teruggaf, zou een transform die maar om één plan geeft vanzelf `options.filter(...)` schrijven en onderweg stilzwijgend de plannen van elke andere app verwijderen. Met setters kun je alleen je eigen bewerkingen beschrijven: patches worden samengevoegd per plan en per veld, en de laatste schrijver wint een echt conflict op hetzelfde veld van hetzelfde plan. Een transform die een fout gooit draagt niets bij, en de andere worden nog steeds toegepast.

Elke transform ziet de *originele* opties, geen half-gepatcht beeld, dus registratievolgorde verandert niet wat je leest.

<Note>
  De planvolgorde blijft zoals Shopify hem teruggaf, dus een transform kan niet herordenen. Om te bepalen welk plan als eerste wordt aangeboden (en waarop de eenmalige-upgradeknop abonneert), gebruik je [`registerDefaultSubscriptionOptionSelector`](#registerdefaultsubscriptionoptionselector), die zijn keuze naar voren promoveert.
</Note>

Je kunt ook geen plan *toevoegen* of een prijs veranderen: `discountPercent` heeft geen setter, omdat een plan dat Shopify bij de checkout niet honoreert gewoon een gebroken belofte in de kiezer zou zijn.

<div id="registerdefaultsubscriptionoptionselector">
  ## registerDefaultSubscriptionOptionSelector
</div>

Kies welk plan op een regel is voorgeselecteerd. Geef een plan-`id` terug, of `null` om te passen.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.hooks.registerDefaultSubscriptionOptionSelector((options) => {
  const best = options
    .slice()
    .sort((optionA, optionB) => optionB.discountPercent - optionA.discountPercent)[0];
  return best ? best.id : null;
});
```

De **eerste selector die de id van een beschikbaar plan teruggeeft wint**, dus geef `null` terug voor de regels waar je niet om geeft in plaats van te gokken. Dat geeft de beslissing door aan de volgende selector in plaats van hem te overschrijven. Een id die met geen enkel plan op de regel overeenkomt wordt hetzelfde behandeld als `null` en geeft ook door, dus een verouderde id kan de kiezer niet blank maken.

Je functie ontvangt `(options, context)`, dezelfde `context` die de options-transform krijgt.

<div id="registerskipaddtocartrule">
  ## registerSkipAddToCartRule
</div>

Geef `true` terug om een specifiek productformulier normaal aan de winkelwagen te laten toevoegen en Aftersell volledig te omzeilen. Dit is handig voor een formulier dat zijn eigen redirect of afhandeling nodig heeft.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.hooks.registerSkipAddToCartRule((form) =>
  form.hasAttribute('data-skip-aftersell')
);
```

**Elke `true` slaat over**, dus houd je regel smal, gericht op de specifieke formulieren die je zelf beheert, en geef `false` terug voor al het andere. Regels worden geëvalueerd in registratievolgorde en stoppen bij de eerste `true`, dus stop er geen bijeffecten in: of de jouwe überhaupt draait, hangt af van wat er vóór hem is geregistreerd.

<Tip>
  Als je de markup van het formulier beheert, heb je helemaal geen hook nodig: voeg de class **`aftersell-cart-skip-atc`** toe aan het `<form>` en Aftersell laat het met rust. Gebruik deze hook wanneer je de markup niet kunt bewerken, of wanneer de beslissing afhangt van iets dat alleen jouw code weet.
</Tip>

**Gebruik het voor:** een pre-order- of offerteformulier dat zijn eigen redirect nodig heeft, de aangepaste flow van een abonnementsapp, een "buy it now"-knop die rechtstreeks naar de checkout moet gaan. Om interceptie voor de hele pagina uit te schakelen, gebruik je in plaats daarvan [`skip_add_to_cart_interceptor`](/nl/aftersell/cart/sdk-configure#skip_add_to_cart_interceptor), maar geef de voorkeur aan deze hook, die beperkt is tot de formulieren die je benoemt.

<div id="where-to-go-next">
  ## Waar nu naartoe
</div>

* **[Cart-object](/nl/aftersell/cart/sdk-cart-object)**: de vorm van de regel die een transform ontvangt.
* **[Events](/nl/aftersell/cart/sdk-events)**: alles waarop je je kunt abonneren.
* **[Actions](/nl/aftersell/cart/sdk-actions)**: de winkelwagen lezen en wijzigen.
* **[Use cases](/nl/aftersell/cart/sdk-use-cases)**: complete oplossingen voor veelvoorkomende verzoeken.
