Filter products by price using Ajax in Shopify with Liquid code

I am looking to implement a custom product price filtering feature for my collection without relying on an app. Unlike the traditional price filter option, I want users to be able to input any combination of numbers, such as between $4 and $20 or $7 and $30, that they can modify themselves. I have witnessed this functionality on a Shopify site, so I know it is achievable with some AJAX calls.

Although I came across a related question on StackOverflow (Add price filter in shopify?), it did not fully address my requirements. The ability to customize price ranges dynamically seems to be a fundamental necessity that has yet to receive a clear solution on platforms like SO and Shopify forums. Any guidance, even if high-level rather than specific code, would greatly benefit myself and others seeking similar customization. Just to clarify, I am utilizing the default (debut) theme.

Answer №1

Our projects share similarities, so please complete the section below.

Develop a collection template collection.price-filter.liquid
Utilize ajax to retrieve the products json. Keep in mind that there is a limit of 250 products. If you have more than 250 products, consider using an app to filter the results first or make multiple requests.

<script>
    var allProducts;
    var filteredProducts = [];
    var activeFilter = [];
    $(document).ready(function(){
        var url = '{{collection.url}}/products.json?limit=250';
        const res = getProducts(url);
    });

    function getProducts(url){
        $.ajax({
            type: 'GET',
            url: url,
            success: function(res){ 

                allProducts = res.products;
                filterProducts(allProducts);
            },
            error: function(status){
                 alert(status);
            }
        });
    }
</script>

Implement filters to populate the filteredProducts array with product objects

//iterate through products, creating categories ($20-$40, $40-$60, etc.)
function filterProducts(products){
    var cat1 = '20-40', cat2 = '40-60';
    var currentCat;
    products.forEach(function (i, j){   
        if (i.price > 20 && i.price <= 40){
            currentCat = cat1;
        else if (i.price > 40 && i.price <= 60) {
            currentCat = cat2;
        }
            if(filteredProducts[currentCat]){
                filteredProducts[currentCat].push(i);
            }
            else {
                filteredProducts[currentCat] = [i]
            }
        };
    });
}

Once filteredProducts is generated, monitor User's checkbox selections and add them to an array named activeFilter

function getActiveFilter(){
    $('#myFilter').each(function(){
        if($(this).is(':checked')){
            //add to activeFilter
        }
    });
}

Create resultFilter from filteredProducts and activeFilter, eliminating common results;

function resultFilter(){
    var result = [];
    activeFilter.forEach(function (i, value){
        Object.keys(value).forEach(function(j, product){
            //add to result
        };
    });
}

Display product results using handlebars.js

<script id="ProductTemplate" type="text/x-handlebars-template">
  {% raw %}
    {{#product}}
        <div class="col">
          <a href="/products/{{productHandle}}" class="grid__image">
            <div class="product__image-wrapper" style="background-color: white;">
              <img class="no-js lazyload" width="316" height="237"
                data-src="{{ featuredImg }}"
                data-widths="[108, 360, 375, 414, 568, 684, 720, 732, 736, 768, 1024, 1200, 1296, 1512, 1728, 1944, 2048]"
                data-aspectratio="1.33"
                data-sizes="auto"
                data-parent-fit="width"
                alt="{{ title }}">
            </div>
          </a>
          <p class="h5"><a href="/products/{{productHandle}}">{{ title }}</a></p>
        </div>
    {{/product}}
   {% endraw %}
</script>

Insert data into #container-products, where you want the filtered Products to show.

function buildFilteredProducts(filteredProds) {
        var $productContainer = $('#container-product');
        $productContainer.empty();
        if(filteredProds.length <= 0){
            $productContainer.append('empty result');
            return;
        }

        var products = [];
        var product = {};
        var data = {};
        var source = $("#ProductTemplate").html();
        var template = Handlebars.compile(source);
        products = filteredProds.map(function(productItem) {
            return product = {
            id: productItem.id, 
            title: decodeHtml(productItem.title),
            featuredImg: responsiveImage(productItem.images[0].src),
            productHandle: productItem.handle
            }
        });

        data = {
            product: products
        } 

        $productContainer.append(template(data)); 
    }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Can someone provide guidance on how to send serialized data using a jQuery.getScript() request?

Is it feasible to make a request for an external JS file while simultaneously sending serialized data in that same request? I want to provide some values to validate the request, but without including those values in the request URL. Upon receiving the po ...

Invoking a Vuex action inside another Vuex action

After transitioning to the Vuex store, I've been steadily moving forward. However, my current hurdle involves invoking an action from within another action in Vuex. My grasp on Vue.js is still a work in progress. Current versions Vue 3 Vuex 4 If nec ...

Display a pop-up window when hovering over a table cell using HTML and JavaScript

I am currently developing a JavaScript application and came across a helpful library called qtip2. My objective is to have different information displayed when the user hovers over each cell in the table. The qtip2 library I mentioned earlier can display ...

Unable to comprehend the reason why the PHP file is not being invoked by Ajax

Here is the code snippet from my HTML file: <script> $(document).ready(function (event) { $(document).on("click", ".interestbutton", function(e) { var docID = e.target.parentNode.parentNode.id; $.ajax( ...

What are some ways to optimize Ajax requests for improved speed when multiple identical requests are made on a single webpage?

When the webpage is loaded, a block is dynamically created using an Ajax call to retrieve data from another page. This structure is then populated and added to a specific DOM element. However, multiple Ajax calls during page loads are causing delays. Is ...

Securing a namespace using passport js: A step-by-step guide

Imagine I have set up a specific route with the following namespace: app.use('/registered', userRoute); Recently, I wrote the following passportjs function: app.get('/logged/dashboard', function (req, res) { if (req.user === undefi ...

Issue with Promise rejection not being caught in Node.js with ExpressNode.js and Express are not

Within my Express web application, I've created a function that outputs a Promise object. login: function(un, pass) { result = {}; var loginOk = new Promise( function (resolve, reject) { if (result.hasOwnPr ...

Filtering properties of objects in Vue

I am currently dealing with an array of objects that represent continents: data() { return { continents: [ { name: "South America", countries: [ { name: "P ...

Using a combination of look-arounds and tag omission for advanced parsing

I am trying to identify text that is not part of another word (which I have working successfully), but I also want to ensure that the text is not inside an <a> tag. "Java <li>Javascript</li> <a href="">Some Java here</a> more ...

Tips for ensuring the directive stays current with changes to the parent scope variable

Example: <div ng-show="{{ display }}"> ... </div> angular.module('mymodule').directive('mydirective', [ function () { return { scope: { display: '=' }, ... }; ...

I am having trouble getting the filter functionality to work in my specific situation with AngularJS

I inserted this code snippet within my <li> tag (line 5) but it displayed as blank. | filter: {tabs.tabId: currentTab} To view a demo of my app, visit http://jsfiddle.net/8Ub6n/8/ This is the HTML code: <ul ng-repeat="friend in user"> ...

What is the process of saving a model with @tensorflow/tfjs-node version 2?

I've been struggling with setting up the save handler to save my model. I've scoured through various platforms like stack overflow and GitHub, but haven't had any luck. Help! Any guidance would be greatly appreciated!!! :) Below is a snipp ...

Guide to sending a post request with parameters in nuxt.js

I am trying to fetch data using the fetch method in Nuxt/Axios to send a post request and retrieve specific category information: async fetch() { const res = await this.$axios.post( `https://example.com/art-admin/public/api/get_single_cat_data_an ...

Finding the index of a row using jQuery

I am encountering an issue with the following code: $("#myTable td").each(function(){ if($(this).html()=="") { rIndex1=$(this).parent().index(); //this value remains "1" rIndex2=$(this).rowIndex; //this value stays as "undefined" Un ...

Creating a sliding bottom border effect with CSS when clicked

Is there a way to animate the sliding of the bottom border of a menu item when clicked on? Check out the code below: HTML - <div class="menu"> <div class="menu-item active">menu 1</div> <div class="menu-item">menu 2</ ...

I desire for both my title and navigation bar to share a common border-bottom

As I embark on my journey into the world of HTML and CSS, my knowledge is still limited. Despite trying various solutions from similar queries, none seem to resolve my specific issue. What I yearn for is to have both my title and navigation bar share the s ...

When attempting to retrieve information using the findById(''), the process became frozen

When attempting to retrieve data using findById(), I'm encountering a problem. If I provide a correct ObjectID, the data is returned successfully. However, if I use an invalid ObjectID or an empty string, it gets stuck. If findById() is called with a ...

"Process the contents of a file by reading it line by line in a

Currently, I am reviewing the documentation for the nodejs readline module in order to tackle a task that involves reading a very large file line by line. The solution using readline seems promising, although I require it to read lines synchronously - mean ...

Difficulty displaying a progress bar over an overlay

Issue with Progress Bar Visibility in AJAX Call: I have a requirement to display a progress bar in an overlay after the save button is clicked. However, the progress bar is only visible after we receive the response from the AJAX call and display an aler ...

When a node using express encounters :id, it is directed to a specific location

Currently, I am in the process of creating a small API collection to familiarize myself with nodejs using express. In my project, I have included the line app.use("/v1/phrases", phraseRouter); Within the router file, the code looks like this: co ...