I’m creating a cart-drawer for my Shopify theme. The drawer currently have all the cart line items listed in it with a forloop like so
<ul>
{% for item in cart.items %}
{% render 'ajax-cart-item-template' with item: item, data_line_index: forloop.index, for_drawer: true %}
{% endfor %}
</ul>
I need to add the feature of "Whenever someone clicks on add to cart button, the drawer will automatically open and the item will be added to it"
So what I’m trying to achieve is something like this
var cart_item = document.createElement('div');
cart_item.innerHTML = "{% include 'ship-cart-line-item' with item: '" + r.items[0] + "', data_line_index: '" + r.items[0].id + "', for_drawer: true %}";
cartDrawer.appendChild(cart_item);
Where r is an array containing 1 object that is the product that we added
After searching I tried to add in addToCart function the following code:
var newDiv = document.createElement('div');
newDiv.innerHTML = `{% raw %}{% include 'cart-line-item' %}{% endraw %}`;
cartDrawer.appendChild(newDiv);
But it returned the liquid code as a plain string in the drawer
(without adding `, it says that raw is not defined)
Then I tried to fetch the snippet from Shopify and add the parameters I need to it like so
var cart_item = document.createElement('div');
var include_url = '{{ "ship-cart-line-item" | include }}';
fetch(include_url + '?item=' + JSON.stringify(r.items[0]) + '&data_line_index=' + r.items[0].id + '&for_drawer=true')
.then(function(response) {
return response.text();
})
.then(function(html) {
cart_item.innerHTML = html;
var parent = document.getElementById('cartDrawer');
parent.appendChild(cart_item);
});
Then I tried to load the content of the snippet into a variable using AJAX then passing the parameters & appending the result to the parent, cart drawer
const cartDrawer = document.getElementById("cart-drawer");
const cart_item = document.createElement("div");
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
cart_item.innerHTML = this.responseText;
cartDrawer.appendChild(cart_item);
}
};
xhr.open("GET", "{% render 'cart-line-item', item: r.items[0], data_line_index: r.items[0].id, for_drawer: true %}", true);
xhr.send();
But I’ve got an error saying 995fe33we7716795p70e72afbmd3a6af29l.js:2 GET https://www.example.com/products/%7B%%20render%20'cart-line-item',%20item:%20r.items[0],%20data_line_index:%20r.items[0].id,%20for_drawer:%20true%20%%7D 400 e.send
I read about alternate template, but I still didn’t know how to correctly apply it. I added this script to fetch the handlebar that makes the template out of a snippet and I included it inside theme.liquid
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.7/handlebars.min.js"></script>
Then created a snippet called "ajax-cart-line-item.liquid" and I copied and pasted the cart-line-item.liquid code inside of it and wrapped them all with a script tag like so
<script id="cart-line-item-template" type="text/x-handlebars-template">
<li> ...</li>
</script>
Then inside addToCart function, the click event listener, I added the following code
let cart_item = document.createElement('div');
const source = document.getElementById("cart-line-item-template").innerHTML;
const template = Handlebars.compile(source);
let item = r.items[0]
const html = template({ item });
cart_item.innerHTML = html;
cart_drawer_content.appendChild(cart_item)
cart_drawer.setAttribute('aria-hidden', 'false')
But I got an error saying "Cannot read property innerHTML of null", to solve that I tried to include the new snippet (ajax-cart-line-item.liquid) inside the cart drawer instead of "cart-line-item" but that resulted the page to be refreshed on each quantity selector change or deleting an item.
<ul>
{% for item in cart.items %}
{% render 'ajax-cart-item-template' with item: item, data_line_index: forloop.index, for_drawer: true %}
{% endfor %}
</ul>
I noticed that inside the devtools when I added "ajax-cart-item-template", the <li>
elements (each cart line item is an <li>
and they’re all wrapped inside the script tag as mentioned before) but the <li>
elements are not inside the script tag in the DOM although it’s correctly implemented in the code
I would appreciate any help!
2
Answers
I found my answer in this YouTube video https://youtu.be/AfhM409bOEM
I created a template inside templates folder, I chose index from the dropdown then named the file "index.cart.liquid" with no layout like so ```{% layout none %}, I copied the cart content that should be updated and pasted it inside the template.
Then on each addToCart or updateCart I fetched /?view=cart
This will fetch the content of the template and change the innerHTML of the drawer to the updated cart items, view=cart is coming from the naming of the template
Note: you can access the template content by going to "www.example.com?view=cart"
You might use the Section rendering API which allows you to query the content of a specific section (won’t work with a snippet) and then use it in the response:
https://shopify.dev/docs/api/section-rendering
It has been created for that.