Discuss and resolve questions on Liquid, JavaScript, themes, sales channels, and site speed enhancements.
Hello Shopify Community,
I hope this post finds you well. I am reaching out to seek assistance with an issue I am currently facing in my Shopify store related to the integration of Flatpickr for date selection and updating the cart with the selected variant ID.
I have implemented a date picker using Flatpickr that allows users to select booking dates. The logic is designed to determine the appropriate variant based on the selected date range, and it successfully updates the variant selector and displayed price accordingly. However, when attempting to add the product to the cart, I am encountering a "400 Bad Request" error, indicating an issue with the selected variant ID being posted to the cart.
POST https://pro-sound-and-lighting.myshopify.com/cart/add.js?id=1%20Week&quantity=1&oseid=NSa28yXZX8Q7AskYMTv3hbju 400 (Bad Request)
The issue seems to be related to how the variant ID is constructed and passed to the cart during the addToCart function. The selectedVariantId is not being formatted or encoded correctly, resulting in a failed request.
I would greatly appreciate any guidance or assistance from the community in identifying and resolving this issue. Here are some specific questions:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<!-- flatpickr -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
<title>DateSelector</title>
</head>
<body class="vh-100">
<!-- Main Content -->
<div class="mx-auto" style="margin-top:2.71px;margin-bottom:2.71px;">
<label class="form_label dates_label">Booking Dates</label>
<form>
<div class="date-picker-wrap date-pick-v3">
<div class="date-picker-custom book-from">
<label for="start_date" class="start-date">Book From:</label>
<input type="text" id="start_date" class="form-control required" autocomplete="off" name="properties[Start Date]" form="product-form-{{ section.id }}" placeholder="" required>
</div>
<div class="booking-separator"></div>
<div class="date-picker-custom book-to">
<label for="end_date" class="end-date">Book To:</label>
<input type="text" id="end_date" class="form-control required" autocomplete="off" name="properties[End Date]" form="product-form-{{ section.id }}" placeholder="" required>
</div>
</div>
</form>
<!-- Displayed Price -->
<div class="price__regular">
<span class="visually-hidden visually-hidden--inline">{{ 'products.product.price.regular_price' | t }}</span>
<span id="displayed_price" class="price-item price-item--regular"> {{ money_price }} </span>
</div>
</div>
<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<!-- flatpickr -->
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
<!-- Your Shopify script with Flatpickr integration -->
<script>
document.addEventListener('DOMContentLoaded', function () {
let selectedVariantId;
const start_date = flatpickr("#start_date", {
enableTime: false,
allowInput: true,
dateFormat: "d M",
altInput: false,
altFormat: "j F, Y",
minDate: "today",
disable: [
function(date) {
// Disable Sundays
return date.getDay() === 0;
}
],
minTime: "09:00",
maxTime: "17:00",
onChange: function (sel_date, date_str) {
// Set maxDate for end_date to one week from the selected start date
const maxEndDate = new Date(sel_date);
maxEndDate.setDate(maxEndDate.getDate() + 7); // Maximum 7 days from the selected start date
end_date.set("minDate", date_str);
end_date.set("maxDate", maxEndDate);
updateProductVariant();
}
});
const end_date = flatpickr("#end_date", {
enableTime: false,
allowInput: true,
dateFormat: "d M",
altInput: false,
altFormat: "j F, Y",
minDate: "today",
disable: [
function(date) {
// Disable Sundays
return date.getDay() === 0;
}
],
minTime: "09:00",
maxTime: "17:00",
onChange: function (sel_date, date_str) {
updateProductVariant();
}
});
function updateProductVariant() {
// Logic to select product variant based on date range
const start = start_date.selectedDates[0];
const end = end_date.selectedDates[0];
const daysDifference = Math.floor((end - start) / (24 * 60 * 60 * 1000)) + 1;
let selectedVariant = "1 Night";
if (daysDifference >= 3 && daysDifference <= 4) {
selectedVariant = "2-3 Nights";
} else if (daysDifference >= 5) {
selectedVariant = "1 Week";
}
const variantSelector = document.querySelector('.select__select');
// Find the option with the matching variant name
const variantOption = Array.from(variantSelector.options).find(option => option.text === selectedVariant);
if (variantOption) {
// Set the selected variant in Shopify variant select
variantSelector.value = variantOption.value;
// Trigger a change event to ensure Shopify updates the product variant
variantSelector.dispatchEvent(new Event('change'));
// Fetch and update the displayed price based on the selected variant
const displayedPriceElement = document.getElementById('displayed_price');
const selectedVariantPrice = fetchVariantPrice(selectedVariant); // Implement this function
displayedPriceElement.textContent = selectedVariantPrice;
// Update the selectedVariantId
selectedVariantId = variantSelector.value;
}
}
const cartButton = document.getElementById('ProductSubmitButton-template--14892119556214__main');
if (cartButton) {
cartButton.addEventListener('click', addToCart);
}
function addToCart() {
console.log('Selected Variant ID:', selectedVariantId);
const encodedVariantId = encodeURIComponent(selectedVariantId);
const addToCartUrl = `https://prosoundlighting.com.au/cart/add.js?id=${encodedVariantId}&quantity=1`;
fetch(addToCartUrl, { method: 'POST' })
.then(response => response.json())
.then(data => {
console.log('Product added to cart:', data);
// Handle success, e.g., display a success message
})
.catch(error => {
console.error('Error adding product to cart:', error);
// Handle error, e.g., display an error message
});
}
// Function to fetch the price of the selected variant
function fetchVariantPrice(selectedVariant) {
// Replace this with your logic to fetch the price based on the selected variant
// Example: return a hardcoded price for the selected variant
const regularPrice = parseFloat("{{ product.price | money_without_currency }}".replace(',', '')); // Replace with your actual Shopify liquid code
switch (selectedVariant) {
case "1 Night":
return formatPrice(regularPrice);
case "2-3 Nights":
return formatPrice(regularPrice * 1.5);
case "1 Week":
return formatPrice(regularPrice * 3);
default:
return formatPrice(regularPrice * 3);
}
}
// Helper function to format the price
function formatPrice(price) {
// Replace this with your logic to format the price (e.g., add currency symbol, decimal places, etc.)
return "$" + price.toFixed(2);
}
});
</script>
</body>
</html>
I have tried various approaches but haven't been able to resolve the issue on my own. Any insights or suggestions from the community would be immensely helpful.
Thank you in advance for your time and assistance.
Kindest regards,
Josh
I can see you're already trying to debug this and you've got this line:
console.log('Selected Variant ID:', selectedVariantId);
What's the value being shown in that console log? Without seeing the site it's hard to be sure what values are actually in the dropdown or know if the variant ID is being pulled or not.
The fact the url you've shown has an ID of 1, I could guess and say it's getting the index value and not the variant id.
Hello @Jason Appreciate your quick response!
Apologies I did not add this to the post, the console log is:
Selected Variant ID: 1 Week
I have the feeling I might be grabbing the variant name instead by targeting the variant picker class?
Would there maybe be a way to use a prefix to reference the selected variant name taken from the picker to search the application/json for the corresponding id?
const variantSelector = document.querySelector('.select__select');
I have also decided to publish the theme temporarily if you would be so kind to check it out it would mean a lot! 🙂
https://prosoundlighting.com.au/products/ultimate-dance-package
As 2024 wraps up, the dropshipping landscape is already shifting towards 2025's trends....
By JasonH Nov 27, 2024Hey Community! It’s time to share some appreciation and celebrate what we have accomplis...
By JasonH Nov 14, 2024In today’s interview, we sat down with @BSS-Commerce to discuss practical strategies f...
By JasonH Nov 13, 2024