Batyr

[SOLVED]Price Range filtering in Front end using processwire

Recommended Posts

Posted (edited)

Hi Guys, Recently I was working on my new project and I need to implement price range filtering. I am using noUiSlider which came with the template that I have purchased. How can I pass values of minimum and maximum values using ajax? I am using foreach loop as shown in code in the code

<ul class="row shop list-unstyled" id="grid">
                    <!-- product -->
                    <?php $result = $pages->get("/sadakalar")->children();?>
                    <?php foreach ($result as $r): ?>
                        <li class="col-sm-4 col-md-3 col-lg-3 product m-product" data-groups='["bedroom"]'>
                            <div class="img-bg-color primary">
                                <h5 class="product-price" data-price="<?=$r->price;?>"><?=$r->price_range->max;?> manat</h5>
                                <a href="<?=$r->url;?>" class="product-link"></a>
                                <!-- / product-link -->
                                <img src="<?=$r->image->first()->url;?>" alt="<?=$r->image->description;?>">
                                <!-- / product-image -->

                                <!-- product-hover-tools -->
                                <div class="product-hover-tools">
                                    <a href="<?=$r->url;?>" class="view-btn" data-toggle="tooltip" title="Giňişleýin gör">
                                        <i class="lnr lnr-eye"></i>
                                    </a>
                                    <!--<a href="shopping-cart.html" class="cart-btn" data-toggle="tooltip" title="Add to Cart">
                                        <i class="lnr lnr-cart"></i>
                                    </a>-->
                                </div><!-- / product-hover-tools -->

                                <!-- product-details -->
                                <div class="product-details">
                                    <h5 class="product-title"><?=$r->title;?></h5>
                                    <!--<p class="product-category">Hemme zat içinde</p>-->
                                </div><!-- / product-details -->
                            </div><!-- / img-bg-color -->
                        </li>
                    <!-- / product -->
                    <?php endforeach; ?>
                    <!-- sizer -->
                    <li class="col-sm-4 col-md-3 col-lg-6 shuffle_sizer"></li>
                    <!-- / sizer -->

                </ul> <!-- / products -->

Here is the code of my range slider: Values of min and max values are stored inside of <span>

<!-- filter-by-price widget -->
                <div class="widget">
                    <h5 class="widget-title">Baha boýunça saýhalla</h5>

                    <div id="range-slider" class="noUi-target noUi-rtl noUi-horizontal">
                    </div><!-- / range-slider -->

                    <div class="range-filter">
                        <div class="column filter-button">
                            <button type="submit" class="btn btn-xs btn-default-filled btn-rounded" id="filter">Saýhalla</button>
                        </div> <!--/ filter-button -->
                        <div class="column range-values">
                            <p>$<span class="value" id="range-slider-value-min"></span> - $<span class="value" id="range-slider-value-max"></span></p>
                        </div><!-- / range-values -->
                    </div><!-- / range-filter -->
                    <!-- / filter-by-price widget -->

And lastly here is my javascript of which handles the changes in noUiSlider:

<script>
var limitSlider = document.getElementById('range-slider');

noUiSlider.create(limitSlider, {
    start: [ 100, 5000 ],
    limit: 10000,
    behaviour: 'drag',
    connect: true,
    range: {
        'min': 0,
        'max': 10000
    }
});

var limitFieldMin = document.getElementById('range-slider-value-min');
var limitFieldMax = document.getElementById('range-slider-value-max');
var dataString = limitFieldMin + limitFieldMax;

limitSlider.noUiSlider.on('update', function( values, handle ){
    (handle ? limitFieldMax : limitFieldMin).innerHTML = values[handle];
});

</script>

So what I want to do is, whenever user slides the range filter, it automatically throws the filtered products. I have also attached the picture of my website. Any help is greatly appreciated. Thank you in advance!

Снимок.PNG

Edited by Batyr
I found the way to do it.

Share this post


Link to post
Share on other sites
Posted (edited)

To get you started, I give you an example of an ajax request triggered by a noUiSlider's event which update the markup.

Do not hesitate to ask if you don't understand something.

 

Javascript code :

// slider element
var slider = document.getElementById('noUiSlider');
// create the slider object
noUiSlider.create(slider, {
    start: [0, 100],
    step: 1, // avoid float values
    range: {
        'min': 0,
        'max': 100
    }
});
    
// change the value when noUiSlider values are updated
slider.noUiSlider.on('update', function( values, handle ) {
    if ( handle ) {
    	$("#noUiSlider-data").data("max", values[handle]);
    } else {
    	$("#noUiSlider-data").data("min", values[handle]);
    }
});

// on event 'set' send ajax request
slider.noUiSlider.on('set', function( values, handle ) {
    // get the min and max from the data attribute of #noUiSlider-data
    $data = {min: $("#noUiSlider-data").data("min"), max: $("#noUiSlider-data").data("max")};
    // ajax request
    $.ajax({
    	url: $(this).data('url'), // url from the data attribute of #noUiSlider
    	type: "post",
	data: $data
  	}).done(function (response, textStatus, jqXHR) {
		$('#list').html(response); // write markup to #list element
  	})
});

 

PHP code  :

<?php namespace ProcessWire;

$list = '';
$limit = 100;
if(isset($input->post->min) && isset($input->post->max)) {
    $min = $input->post->min; // don't forget to sanitize
    $max = $input->post->max; // don't forget to sanitize
    $li = '';
    $products = $pages->find("template=product, start=$min, limit=$max"); // let assume there is a template 'product'
    foreach ($products as $product) {
        $li .= "<li>". $product->title . "</li>";
    }
    $list = "<ol>$li</ol>";
    echo $list;
}
?>

 

HTML Markup :


<div id="noUiSlider" data-url="<?= $page->url; ?>"></div>
<span id="noUiSlider-data"></span>
<div id="list">
    <?= $list ?>
</div>

#noUiSlider is the slider element

#noUiSlider-data will contain values changed from the #uiSlider element

#list is the element updated by the ajax response

 

enjoy

 

nouislider.gif.1fcce3ae6c26f55826df674de7905023.gif

Edited by flydev
screenshot
  • Like 11

Share this post


Link to post
Share on other sites

Hi @flydev Thank you, this is indeed a great solution. But for my case I used another tactic, using the search technique, so my PHP code looks like this:

<ul class="row shop list-unstyled" id="grid">
                    <?php 
                         // search.php template file
                        // look for a GET variables named 'min', 'max' and sanitize it
                        $min = $sanitizer->text($input->get->min); 
                        $max = $sanitizer->text($input->get->max);

                        
                          // did $min and $max have anything in it?
                        
                            if($min and $max){ 
                              // Send our sanitized query 'min', 'max' variable to the whitelist where it will be
                              // picked up and echoed in the search box by _main.php file. Now we could just use
                              // another variable initialized in _init.php for this, but it's a best practice
                              // to use this whitelist since it can be read by other modules. That becomes 
                              // valuable when it comes to things like pagination. 
                              $input->whitelist('min', $min); 
                              $input->whitelist('max', $max);
                              // Sanitize for placement within a selector string. This is important for any 
                              // values that you plan to bundle in a selector string like we are doing here.
                              $min = $sanitizer->selectorValue($min);
                              $max = $sanitizer->selectorValue($max);
                              // Search the title and body fields for our query text.
                              $selector = "price>=$min , price<=$max"; 
                              //if($user->isLoggedin()) $selector .= ", has_parent!=2"; 
                              // Find pages that match the selector
                              $items = $pages->find($selector); 
                              // did we find any matches?
                                  if($items->count) {
                                  $count = "Görkezilen baha boýunça jemi $items->count sanysy tapyldy";
                    ?>
                    <!-- product -->
                    <p class="shop-results space-left"><strong><?=$count;?></strong> </p>
                    <?php foreach ($items as $match): ?>
                        <li class="col-sm-6 col-md-3 col-lg-3 product m-product" data-groups='["bedroom"]'>
                            <div class="img-bg-color primary">
                                <h5 class="product-price"><?=$match->price;?> manat</h5>
                                <a href="<?=$r->url;?>" class="product-link"></a>
                                <!-- / product-link -->
                                <img src="<?=$match->image->first()->url;?>" alt="<?=$match->image->description;?>">
                                <!-- / product-image -->

                                <!-- product-hover-tools -->
                                <div class="product-hover-tools">
                                    <a href="<?=$match->url;?>" class="view-btn" data-toggle="tooltip" title="Giňişleýin gör">
                                        <i class="lnr lnr-eye"></i>
                                    </a>
                                    <!--<a href="shopping-cart.html" class="cart-btn" data-toggle="tooltip" title="Add to Cart">
                                        <i class="lnr lnr-cart"></i>
                                    </a>-->
                                </div><!-- / product-hover-tools -->

                                <!-- product-details -->
                                <div class="product-details">
                                    <h5 class="product-title"><?=$match->title;?></h5>
                                    <!--<p class="product-category">Hemme zat içinde</p>-->
                                </div><!-- / product-details -->
                            </div><!-- / img-bg-color -->
                        </li>
                    <!-- / product -->
                    <?php endforeach; } } else { ?>
                    <!-- product -->    
                    <?php foreach ($result = $page->children() as $r): ?>
                        <li class="col-sm-6 col-md-3 col-lg-3 product m-product" data-groups='["bedroom"]'>
                            <div class="img-bg-color primary">
                                <h5 class="product-price"><?=$r->price;?> manat</h5>
                                <a href="<?=$r->url;?>" class="product-link"></a>
                                <!-- / product-link -->
                                <img src="<?=$r->image->first()->url;?>" alt="<?=$r->image->description;?>">
                                <!-- / product-image -->

                                <!-- product-hover-tools -->
                                <div class="product-hover-tools">
                                    <a href="<?=$r->url;?>" class="view-btn" data-toggle="tooltip" title="Giňişleýin gör">
                                        <i class="lnr lnr-eye"></i>
                                    </a>
                                    <!--<a href="shopping-cart.html" class="cart-btn" data-toggle="tooltip" title="Add to Cart">
                                        <i class="lnr lnr-cart"></i>
                                    </a>-->
                                </div><!-- / product-hover-tools -->

                                <!-- product-details -->
                                <div class="product-details">
                                    <h5 class="product-title"><?=$r->title;?></h5>
                                    <!--<p class="product-category">Hemme zat içinde</p>-->
                                </div><!-- / product-details -->
                            </div><!-- / img-bg-color -->
                        </li>
                    <!-- / product -->
                    <?php endforeach; 
                     }?>
                    <!-- sizer -->
                    <li class="col-sm-6 col-md-3 col-lg-3 shuffle_sizer"></li>
                    <!-- / sizer -->

                </ul> <!-- / products -->

and Javascript:

var limitSlider = document.getElementById('range-slider');

noUiSlider.create(limitSlider, {
    start: [ 0, 10000 ],
    step: 1,
    behaviour: 'drag',
    connect: true,
    range: {
        'min': 0,
        'max': 10000
    }
});


 var limitFieldMin = document.getElementById('range-slider-value-min');
 var limitFieldMax = document.getElementById('range-slider-value-max');

limitSlider.noUiSlider.on('update', function( values, handle ){
    (handle ? limitFieldMax : limitFieldMin).value = values[handle];
});   

The range filter area in my page is:

<div class="range-filter">
                        <form action="<?php echo $pages->get('template=shop-right')->url;?>" method='get'>
                            <div class="column filter-button">
                                <button type="submit" class="btn btn-xs btn-default-filled btn-rounded">Saýhalla</button>
                            </div> <!--/ filter-button -->
                            <div class="column range-values">
                                <input type="text" class="value" name="min" size="6" id="range-slider-value-min" value="">
                                <input type="text" class="value" name="max" size="6" id="range-slider-value-max" value="">
                            </div><!-- / range-values -->
                        </form>
</div><!-- / range-filter -->

So whenever I press button 'sort' which is 'sayhalla' in my example, all the values are posted and results are returned as a result. Your case is super as well, it works perfectly but for my template it is better to implement it this way. I tried to implement yours too, but no success. Thank you again!

  • Like 4

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By celfred
      Hello, 
      I've been struggling for hours with this, and it is driving me crazy. I guess I completely misunderstand basic concepts, but I'm facing a wall here hence this message... Here's what I'm trying to do :
      I have a list of players in $allPlayers (pages) Each player has (among others) 2 pageArray fields : 'group' and 'team'. I'm trying to loop through all the players to build another pageArray (or WireArray or whatever...) to gather the players in groups/teams accordingly and deal with the different info I have on them and calculate a score. My main problem is that some players are in a different team but their group has the same name (and I need to restrict players to their own team mates). Here's my 'code' so far (which doesn't work) :
      // Build group list (for players having a team) $allPlayers->filter("team.name!=no-team")->sort("team.name"); $allGroups = new PageArray(); $uniqueGroups = []; $uGroups = new PageArray(); // This was a test, see below... $already = []; foreach($allPlayers as $p) { // Assign a groupId to each player $groupId = $p->team->id.$p->group->id; $p->groupId = $groupId; if (!in_array($groupId, $already)) { // The following lines were a test but didn't work and I DON'T UNDERSTAND WHY ? // $uG = new Page(); // $uG->of(false); // $uG->template = 'player'; // $uG->name = $groupId; // $uGroups->add($uG); // bd($uGroups->count()); // !! Keeps showing 1 ? My purpose was to be able to use $uGroups->karma, $uGroups->nbBonus... afterwards array_push($uniqueGroups, $groupId); } array_push($already, $groupId); } // Then, I loop through $uniqueGroups, get the players and calulate my score foreach($uniqueGroups as $group) { // Limit to groupId players for group scores $players = $allPlayers->find("groupId=$group"); // Check for group bonus and calculate scores [...] // I cut to simplify my post // But my other problem is storing my score : I can't use $group->karma or $group->nbBonus since $group is a ragular PHP array ? } // Then, I wanted to create a new pageArray (hence my $uGroups above) to be able to sort them with the following $uGroups->sort("-karma"); And I'm stuck... More than 5 hours today already on this, and still blocked
      I've tried playing with WireData, WireArray... but I'm all lost here. You can understand why I'm posting in the 'Getting started' forum !
      For further information, this part of code is embedded in a setScoreboard() function and this is the 'group' part of it.
      If anyone can devote a little time to give me a clue on how to think about this, I'd greatly appreciate !
      Thanks !
      PS : The more I write about this, the more I think I am able to get the group members and scores (with my awkward coding), but then I am unable of simply storing this information before rendering it. Here I'm referring to my comment in my code where I say that TracyDebugger keeps showing me only 1 $uGroups page. I wish I could dynamically build a 'uniqueGroup' page with Pagefields for Group, Team, pageArray for Members, Integer fields for calculated Karma, nbBonus...... sigh......  
    • By rgaikema
      Hi everyone,
      Currently I'm struggling with a filter option and I hope somebody can help or advise me the right way to this.

      What I want is an index page where campaigns are shown and where I can filter the campaigns by year.
      Each campaign has a datetime field with the output set to "j F Y", so it shows "1 April 2016" in the frontend.
      The dates are unique for each campaign, but there can be multiple campaigns in the same year.
      The page structure is:
      -client
      --campaign-a
      --campaign-b
      --campaign-c
      --campaign-d
      This is the PHP code I use on the client page to display all the campaigns.
      $campaigns = $page->children("sort=sort"); foreach ($campaigns as $campaign) { if($campaign->campaign_description) { echo '<div class="campaign-description info">'; echo '<h2>' . $campaign->title . '</h2>'; echo '<p>' . $campaign->campaign_description . '</p>'; // Todo remove only for testing $campaignDate = $campaign->campaign_date; $campaignYear = substr($campaignDate, -4); echo '<i>' . $campaignDate . '</i>'; echo '</div>'; } } $campaignYear is where I see the years, 2015, 2016, 2017 and so on.
      Here I create the dropdown to show the unique years:
      if (count($campaigns)) { // Store unique Years $arr = array(); foreach ($campaigns as $campaign) { $campaignDate = $campaign->campaign_date; $campaignYear = substr($campaignDate, -4); $arr[] = $campaignYear; } $unique_years = array_unique($arr); // Show dropdown with unique years echo '<select id="campaign-date-select">'; foreach($unique_years as $year) { echo '<option value="' . $year . '">' . $year . '</option>'; } echo '</select>'; }
      I read a couple of articles, for example this: https://processwire.com/talk/topic/8513-sort-with-select-dropdown/
      but I can't figure out how to dynamically change the output of the campaigns, based on the input of the select options.
      Maybe the datetime field is not the best option, or maybe I have to use URL segments and JavaScript to combine something...
      Any help or advise is welcome!
       
    • By Pete Jones
      We have a big selector which we have broken down into 3 chunks to return a list of notes (pages) with repeaters as follows. We also allow the user to filter the results. The problem we have is that the page currently takes nearly 10 seconds to process results. Is there anything we can do to improve the performance of this? I wonder if it would be worth bringing the filters into each of the find()s. I assume that caching here wouldn't work due to querystring parameters?
      $selector = "template=horse-note"; // Notes with unread comments (date order, most recent first) $notes_with_unread_comments = $pages->find("{$selector}, h_notes_comments.count>0, h_notes_comments.{$session->unread_by}>0, sort=h_notes_last_comment"); //echo 'Notes with unread comments ('.count($notes_with_unread_comments).'):<br />'.$notes_with_unread_comments.'<br /><br />'; // Unread notes (date order, most recent first) $notes_unread = $pages->find("{$selector}, {$session->unread_by}>0, sort=h_notes_last_comment"); //echo 'Notes unread ('.count($notes_unread).'):<br />'.$notes_unread.'<br /><br />'; // Read notes in date order (most recent first) that they were either added or that the last comment was made, whichever is most recent. $notes_other = $pages->find("{$selector}, sort=-h_notes_last_comment"); //echo 'Notes other ('.count($notes_other).'):<br />'.$notes_other.'<br /><br />'; // create notes PageArray $notes_total = new PageArray(); $notes_total->add($notes_other); $notes_total->prepend($notes_unread); $notes_total->prepend($notes_with_unread_comments); // FILTER // sanitize inputs $horse = $sanitizer->text($input->get->horse); $category = $sanitizer->int($input->get->category); $from_date = $sanitizer->text($input->get->from_date); $to_date = $sanitizer->text($input->get->to_date); $comments = $sanitizer->int($input->get->comments); // horse name if($horse) { $selector .= ", parent.h_name%=$horse"; } // note category if($category) { $selector .= ", h_notes_category_id=$category"; } // from date if($from_date) { $selector .= ", h_notes_last_comment>=".strtotime("$from_date 00:00:00"); } // to date if($to_date) { $selector .= ", h_notes_last_comment<=".strtotime("$to_date 23:59:59"); } // comments if($comments) { $selector .= ", h_notes_comments.count>0"; } // apply filter if($selector!='template=horse-note') { $notes_total = $notes_total->find($selector); } // slice PageArray according to pageNum $pageNum = $input->pageNum; $limit = 15; $start = ($pageNum-1)*$limit; $notes = $notes_total->slice($start, $limit);
    • By luckybusted
      Hey guys its me again,
      I'm looking for a solution to show a List of Pages that have the same value in "fieldset-x" as the current Pages "title" e.g. .
      My hardcoded Solution looks like this:
      <?php                              $homepage = $pages->get("/stores/");                 $stores = $homepage->children("location_category=1065, city=1010");                 $children = $stores->getRandom(2);                              foreach($children as $child){                 ... echo ...                 }             ?>  
      Now I need to check the title of the current page "{$page->title}" and check if it is equal to the value of fieldset "city" of a child Page of "Stores" ...
      Any ideas?
    • By onjegolders
      I've been reading up on a few posts on categories but I'm struggling to get them working.
      I saw a video from PW1
      and the example seems nice and simple:Output the categories, click one and the list of entries gets filtered.
      I tried to replicate that but no joy. I can't seem to understand how Ryan can output $page->categories from his page when really the categories are surely part of children()?
      Is it really possible to filter categories of events or news this simply? I've seen other examples in the forums which look much more complex (urlSegments and the like).
      I currently have my category page set up as a child of home, and categories as its children.
      Before seeing that video, I had managed to output the categories like this:
      <div id="events_index_side"> <?php if ($pages->find("template=category")) { ?> <div class="events_index_side_box"> <h5 class="page_header">By category</h5> <ul> <?php $categories = $pages->find("template=category"); foreach ($categories as $category) { ?> <li><a href="<?php echo $page->url . $category->name; ?>"><?php echo $category->title; ?></a></li> <?php } ?> </ul> </div><!-- /.events_index_side_box --> <?php } ?> but using this method, I'm not quite sure how I can get the page to reload with just those categorised entries?
      Would appreciate if anyone could give me a shove in the right direction. Thanks.