Quantity-Based Package Swapper (Standalone)
A fully standalone script that handles quantity controls and package swapping. No SDK selector enhancer needed - this script manages everything directly.
Features
- ✅ Fully Standalone: Handles its own quantity controls, no SDK selector enhancer
- ✅ Zero Conflicts: Doesn't interfere with SDK's PackageSelectorEnhancer
- ✅ Automatic Sync: Syncs selector from cart on page load
- ✅ Flexible Config: Easy quantity → package mapping
- ✅ Multiple Selectors: Support for multiple selectors on one page
- ✅ Debug Logging: Built-in debugging support
- ✅ Zero Flicker: Single cart update per action using
next.swapCart()
Installation
Option 1: Inline Script
<script src="path/to/quantity-package-swapper.js"></script>Option 2: Inline
Copy the script content and paste it in a <script> tag before your closing </body> tag.
Configuration
Edit the QUANTITY_MAPS object in the script. Three formats are supported:
Format 1: Simple (Package ID Only)
Quantity in cart matches selector quantity:
const QUANTITY_MAPS = {
'limos-card': {
1: 2, // Selector qty 1 → Package 2, cart qty 1
2: 3, // Selector qty 2 → Package 3, cart qty 2
3: 4, // Selector qty 3 → Package 4, cart qty 3
}
};Format 2: Custom Quantity
Specify different quantity in cart:
const QUANTITY_MAPS = {
'limos-card': {
1: { packageId: 2, quantity: 1 }, // Selector qty 1 → Package 2, cart qty 1
2: { packageId: 3, quantity: 5 }, // Selector qty 2 → Package 3, cart qty 5
3: { packageId: 4, quantity: 10 }, // Selector qty 3 → Package 4, cart qty 10
}
};Format 3: Multiple Packages
Add multiple packages to cart:
const QUANTITY_MAPS = {
'limos-card': {
1: 2, // Simple format
2: { packageId: 3, quantity: 3 }, // Custom quantity
3: [ // Multiple packages!
{ packageId: 4, quantity: 2 },
{ packageId: 10, quantity: 1 }
],
}
};Mix All Formats
const QUANTITY_MAPS = {
'product-bundle': {
1: 10, // Simple
2: { packageId: 11, quantity: 5 }, // Custom qty
3: [ // Multiple packages
{ packageId: 12, quantity: 2 },
{ packageId: 13, quantity: 1 },
{ packageId: 14, quantity: 1 }
]
}
};Configuration Options
const CONFIG = {
debug: true, // Enable console logging
syncOnLoad: true, // Sync selector from cart on page load
};HTML Setup
Uses custom data-qty-* attributes to avoid conflicts with SDK's native selector system.
<!-- Custom quantity selector (independent from SDK selectors) -->
<div data-qty-selector="limos-card">
<div data-qty-card
data-next-package-id="2"
data-qty-current="1"
data-qty-min="1"
data-qty-max="10">
<!-- SDK display attributes still work -->
<h3 data-next-display="package.name">Product</h3>
<p data-next-display="package.finalPrice">$19.99</p>
<!-- Custom quantity controls -->
<div class="quantity-controls">
<button data-qty-decrease type="button">−</button>
<span data-qty-display>1</span>
<button data-qty-increase type="button">+</button>
</div>
</div>
</div>Required Attributes
Custom Quantity Attributes:
data-qty-selector- Selector ID, must match a key inQUANTITY_MAPSdata-qty-card- Container for the packagedata-qty-current- Current quantity (default: 1)data-qty-increase- Button to increase quantitydata-qty-decrease- Button to decrease quantitydata-qty-display- Element to show current quantity
SDK Attributes:
data-next-package-id- Package ID for SDK display system
Optional Attributes
data-qty-min- Minimum quantity (default: 1)data-qty-max- Maximum quantity (default: 999)
How It Works
On Page Load
- Script waits for
next:initializedevent (SDK ready) - Reads cart via
next.getCartData() - Reverse lookup: Finds which quantity maps to the cart's package ID
- Updates selector UI to match cart state
- Attaches click handlers to quantity buttons
Example:
- Cart has package 4
- Reverse map: package 4 → quantity 3
- Selector updates to show quantity 3
On Quantity Change
- User clicks +/− buttons
- Script's click handler fires (not SDK event)
- Updates quantity display and button states
- Forward lookup: Maps quantity to package ID(s)
- Calls
next.swapCart([{ packageId, quantity }]) - Cart updates with new package(s)
Example:
- User increases to quantity 2
- Forward map: quantity 2 → package 3
- Cart swaps to package 3 with quantity 2
No SDK Selector Conflicts
This script handles quantity controls completely independently from the SDK's PackageSelectorEnhancer. It directly manages click events, so there's no conflict or double updates.
API
The script exposes a global API for manual control:
// Manually sync a selector from cart
QuantityPackageSwapper.syncSelectorFromCart('limos-card');
// Sync all selectors
QuantityPackageSwapper.syncAllSelectorsFromCart();
// Manually swap to a package
await QuantityPackageSwapper.swapToPackage(4, 2);
// Get current cart state
const cart = QuantityPackageSwapper.getCartState();
// Access configuration
QuantityPackageSwapper.config.debug = false;
// Access maps
console.log(QuantityPackageSwapper.maps);Example Workflow
Initial State
HTML: package 2, quantity 1
Cart: empty
Display: Shows package 2 dataUser Action: Click + (3 times)
Quantity: 1 → 2 → 3 → 4
Package: 2 → 3 → 4 → 20 (auto-swapped)
Cart: Updates to package 20, quantity 4Page Refresh
HTML: package 2, quantity 1 (static)
Cart: package 20, quantity 4 (from session)
↓ Script runs ↓
Reverse lookup: package 20 → quantity 4
Selector UI: Updates to show quantity 4
Cart: Unchanged (already correct)Troubleshooting
Selector not syncing on load
Check console for logs:
// Look for:
[QuantitySwapper] Syncing all selectors from cart...
[QuantitySwapper] Found package X in cart → quantity YIf not appearing, check:
- Script is loaded after SDK
syncOnLoad: truein CONFIG- Selector ID matches configuration
Quantity changes not swapping packages
Check console:
[QuantitySwapper] Quantity changed: selector=..., qty=...
[QuantitySwapper] Swapping X → YIf swap not happening:
- Check quantity is in QUANTITY_MAPS
- Verify selector ID matches
- Look for error messages
Enable Debug Mode
// In the script, set:
const CONFIG = {
debug: true, // Shows all operations
syncOnLoad: true,
};Advantages Over Event Listener Approach
| Feature | Event Listener | This Script |
|---|---|---|
| Page load sync | Manual | ✅ Automatic |
| Reverse lookup | Manual | ✅ Built-in |
| Multiple selectors | Manual setup | ✅ Config object |
| Cart method | Manual swap | ✅ Uses swapCart() |
| Flicker | Possible | ✅ None |
| Error handling | Manual | ✅ Built-in |
| Debugging | Manual logs | ✅ Debug mode |
Complete Example
<!DOCTYPE html>
<html>
<head>
<title>Limo Checkout</title>
</head>
<body>
<!-- Custom quantity selector -->
<div data-qty-selector="limos-card">
<div data-qty-card
data-next-package-id="2"
data-qty-current="1"
data-qty-min="1"
data-qty-max="10">
<h3 data-next-display="package.name">Limo Service</h3>
<p data-next-display="package.finalPrice">$19.99</p>
<div class="quantity-controls">
<button data-qty-decrease type="button">−</button>
<span data-qty-display>1</span>
<button data-qty-increase type="button">+</button>
</div>
</div>
</div>
<!-- Campaign Cart SDK -->
<script src="https://cdn.nextcommerce.com/sdk.js"></script>
<!-- Quantity Package Swapper -->
<script>
(function() {
'use strict';
const QUANTITY_MAPS = {
'limos-card': {
1: 2,
2: 3,
3: 4,
4: 20,
}
};
const CONFIG = {
debug: true,
syncOnLoad: true,
};
// ... rest of script ...
})();
</script>
</body>
</html>Notes
- Fully Standalone: Uses custom
data-qty-*attributes, zero conflict with SDK - No SDK Selector Enhancer: No
data-next-cart-selectorneeded - Display Attributes Work: Keep
data-next-displayanddata-next-package-idfor SDK display system - Requires SDK with
next.swapCart()andnext.clearCart()(for cart operations only) - Handles its own quantity button click events
- Package swapping is atomic (single cart update via
swapCart) - Clears cart and resets to quantity 1 on page load
- No SDK modifications required