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

# Gruppér bundle-linjer fra en anden app

> Brug setInternalProperties til at fortælle Aftersell Cart, hvilke linjer der hører til samme bundle, så de renderes som én vare i stedet for flere urelaterede linjer.

De fleste bundle-apps bygger en bundle ved at tilføje **hver komponent som sin egen kurvlinje** og derefter kæde dem sammen med line item properties af eget design. Shopifys Ajax API leverer de linjer til kurven uden nogen indikation af, at de hører sammen, så som standard viser skuffen en tredelt bundle som tre urelaterede varer, hver med sin egen pris og antalsvælger.

`setInternalProperties` er måden, du fortæller kurven, at de er én ting.

<div id="how-grouping-works">
  ## Sådan fungerer gruppering
</div>

Kurven grupperer linjer på to **kanoniske properties**. Den kender ikke din bundle-apps property-navne, så du oversætter: læs hvad appen skrev, og stempl det kanoniske par på hver linje med en [line transform](/da/aftersell/cart/sdk-hooks#registerlinetransform).

| Property                      | Påkrævet | Værdi                                                  |
| ----------------------------- | -------- | ------------------------------------------------------ |
| `_aftersell_cart_bundle_id`   | Ja       | Et delt ID. Hver linje med samme ID er én bundle.      |
| `_aftersell_cart_bundle_role` | Nej      | Sæt til `parent` på den linje, bundlen skal vises som. |

Disse går gennem `setInternalProperties`, ikke gennem Shopify. De er et **render-only overlay**: de når aldrig `properties`, gemmes aldrig i Shopify og vises aldrig på ordren.

<div id="step-1-find-out-what-your-app-writes">
  ## Trin 1: find ud af, hvad din app skriver
</div>

Hver bundle-app navngiver sine properties forskelligt, så start med at kigge på en rigtig kurv. Tilføj en bundle på din storefront, og kør så dette i browserkonsollen:

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.actions.getCart().items.forEach((line) => {
  console.log(line.title, line.properties);
});
```

Du leder efter en property, der deles på tværs af bundlens linjer. Det er normalt en skjult property (navnet starter med `_`), som indeholder et ID, en reference eller bundlens navn. Noget som `_bundle_id`, `_bundle_ref` eller `_parent_id` er typisk. Notér den præcise nøgle, og om én linje er markeret som hovedproduktet.

<div id="step-2-map-it-onto-the-canonical-properties">
  ## Trin 2: map det til de kanoniske properties
</div>

Indsæt i **Cart settings → Custom script → Initialization**, og erstat property-navnene med dem, du fandt:

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.hooks.registerLineTransform((line) => {
  const props = line.properties;
  if (!props) return;

  const bundleId = props._bundle_id;
  if (!bundleId) return;

  line.setInternalProperties({
    _aftersell_cart_bundle_id: bundleId,
    // Mark the main product so the bundle renders under it.
    _aftersell_cart_bundle_role: props._bundle_role === 'main' ? 'parent' : 'child',
  });
});
```

Det er hele integrationen. Så snart to eller flere linjer deler et ID, folder kurven dem sammen til én bundle.

<Note>
  Hvis din app ikke markerer et hovedprodukt, så udelad `_aftersell_cart_bundle_role` helt. Kurven vælger et anker for dig.
</Note>

<div id="what-you-get">
  ## Hvad du får
</div>

Når linjerne er grupperet, bærer ankerlinjen et [`bundle`-objekt](/da/aftersell/cart/sdk-cart-object#bundles), og skuffen renderer bundlen som en enkelt vare:

* **Børn indlejres under ankeret** i stedet for at vises som separate rækker.
* **Antal er atomart.** Ændres bundlens antal, skaleres hvert medlem sammen, ved brug af hvert barns `perAnchorQty`-ratio, så en bundle med to af én komponent bevarer det to-til-en-forhold.
* **Fjernelse er atomar.** Fjernes bundlen, fjernes hver medlemslinje i én forespørgsel, i stedet for at efterlade forældreløse komponenter.
* **Én prisrække.** Hvad den viser, følger **bundle price**-indstillingen på [Cart items](/da/aftersell/cart/cart-items-block)-blokken: totalen for alle medlemmer eller hovedproduktets pris alene.

<div id="how-the-anchor-is-chosen">
  ## Sådan vælges ankeret
</div>

Ankeret er den linje, bundlen vises som. Kurven vælger det i denne rækkefølge:

1. Linjen med `_aftersell_cart_bundle_role` sat til `parent`.
2. Ellers medlemmet med den **højeste pris**.
3. Ellers det første medlem i kurven.

Pris-fallbacken er normalt rigtig, da bundle-apps typisk lægger rabatten på hovedproduktet. Sæt rollen eksplicit, når den ikke er det, for eksempel når hovedproduktet er den billigste vare eller er gratis.

<div id="rules-worth-knowing">
  ## Regler, der er værd at kende
</div>

* **En bundle kræver mindst to linjer.** En enkelt linje med et bundle-ID lades i fred og renderes normalt.
* **Shopifys native bundles er allerede håndteret.** Linjer, som Shopify selv markerer som komponentiserede, springes over af denne gruppering og tilpasses automatisk. Du har kun brug for dette til apps, der tilføjer separate linjer.
* **Transformen kører ved hver render.** Hold den billig og fri for bivirkninger. Kald ikke actions og lav ikke fetch inde fra den.
* **Fletning er additiv.** Dine properties flettes med dem, der er sat af en anden transform. Ved en ægte konflikt om samme nøgle vinder den sidst registrerede transform.
* **Gruppering kører efter skjul og omdøbning**, og før sortering. Så en linje, du skjuler med `setHidden`, bliver aldrig del af en bundle, og en [comparator](/da/aftersell/cart/sdk-hooks#registerlinecomparator) ser ankeret, ikke børnene.

<Warning>
  **Grupperede børn forlader `state.items`.** Når linjer er foldet ind i en bundle, vises kun ankeret i `getCart().items` og i event-payloads; børnene flytter til `anchor.bundle.children`. De tæller heller ikke længere med i `itemCount`.

  **Kurvtotalen påvirkes ikke**, fordi totaler kommer direkte fra Shopify. Gruppering ændrer præsentationen, aldrig hvad kunden betaler.
</Warning>

<div id="reading-a-bundle-back">
  ## Læs en bundle tilbage
</div>

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.events.on('cart_updated', (state) => {
  state.items.forEach((line) => {
    if (!line.bundle) return;
    console.log(line.title, 'is a bundle of', line.bundle.children.length, 'items:');
    line.bundle.children.forEach((child) => {
      console.log('  ', child.quantity, 'x', child.title);
    });
  });
});
```

For at handle på en bundles linjer skal du bruge `bundle.memberKeys`, som indeholder `key` for hvert medlem inklusive ankeret.

<div id="using-it-for-other-things">
  ## Brug det til andre ting
</div>

Bundle-gruppering er det, `setInternalProperties` blev bygget til, men overlayet er en generel kanal for **render-only data, du udleder af en linje**. Alt, du lægger der, kan læses på `line.internalProperties` og i en [Custom code-blok](/da/aftersell/cart/custom-code-blocks), uden at røre den rigtige kurv:

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.hooks.registerLineTransform((line) => {
  if (line.properties?._preorder_ship_date) {
    line.setInternalProperties({ _badge: `Ships ${line.properties._preorder_ship_date}` });
  }
});
```

Brug det, når værdien er **udledt** og kun til visning. Hvis dataene skal overleve til ordren, hører de hjemme i en rigtig line item property, sat med et skjult `properties[...]`-input på produktformularen, så den når Shopify, uanset hvem der udfører tilføjelsen.

<div id="where-to-go-next">
  ## Hvor du kan gå hen herfra
</div>

* **[`registerLineTransform`](/da/aftersell/cart/sdk-hooks#registerlinetransform)**: hooken dette kører igennem.
* **[Cart-objektet](/da/aftersell/cart/sdk-cart-object#bundles)**: formen på `bundle` og dens børn.
* **[Cart items-blokken](/da/aftersell/cart/cart-items-block)**: bundle price-indstillingen.
