Product filters using price range slider and ajax in Laravel
Product filters using price range slider and ajax
Product filters using price range slider and ajax in laravel. Product filters or product filters using price are crucial for modern websites as they provide users with the flexibility to choose products according to their preferences, especially within a specific price range. Filters can be applied based on various criteria such as category, subcategory, tags, groups, colors, size, and more. In this tutorial, we will focus on filtering products within a price range using Laravel, Ajax, and a custom price range slider.
Product filters using price Or Product filters are essential for websites nowadays. They let users pick products within a price range and based on other preferences like category, color, and size. In this tutorial, we’ll learn how to filter products by price range using Laravel, Ajax, and a custom slider. We’ll also add options to filter products by highest and lowest prices. Instead of using third-party slider plugins, we’ll create our own slider with a few lines of JavaScript. Let’s get started by following the steps below.
- Choose between starting a new project or using an existing one.
- Set up the database and connect it to your project.
- Create models and migrations for handling products.
- Update the migration file to include fields for products and run the migration command.
- Add some sample products to the database.
- Define routes required for the application.
- Develop the controller and implement necessary logic for product filtering.
- Design custom CSS and JavaScript for the slider functionality.
- Create the Blade view file for displaying product filters and results.
- Thoroughly test the application to ensure all features work as expected.
Step – 1 : Choose between starting a new project or using an existing one
At the start of the tutorial, we’ll install a new Laravel project. Alternatively, you can integrate these steps into an existing project.
To create a new project named “filters-product” on your machine, use the composer command:
composer create-project laravel/laravel filters-product
Step-2: Set up the database and connect it to your project
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=products
DB_USERNAME=root
DB_PASSWORD=
Step-3: Create models and migrations for handling products
Using the bellow artisan command let’s our model and migration file
php artisan make:model Product -m
Step-4: Update the migration file to include fields for products and run the migration command.
Inside the “database” directory, you’ll find a newly created migration file. Additionally, the “Product.php” model has been generated in the “App\Models” directory. Now, let’s proceed to add all the necessary fields to the “create_products_table.php” migration file, as outlined below.
create_products_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('image')->nullable();
$table->string('name');
$table->text('description')->nullable();
$table->double('price');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('products');
}
};
Step-5: Add some sample products to the database.
Insert some products into the database so that they can be displayed on the frontend and searched by price range. While we won’t focus on the product insertion process, it’s important to ensure that products are available for searching. You can store products in the database manually, use seeders, factories, or upload them via a CSV file, among other methods.
Note: If you’re inserting product images, remember to create an “images” folder inside the public directory.
Step-6: Define routes required for the application.
Just create two routes in web.php file, first one is for displaying all products and second one is for search query
Note : Don’t forget to import your controller at top of the file
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\FilterController;
Route::get('/',[FilterController::class,'all_products'])->name('all.products');
Route::get('/search-product',[FilterController::class,'search_products'])->name('search.products');
Route::get('/sort-by',[FilterController::class,'sort_by'])->name('sort.by');
Step-7: Develop the controller and implement necessary logic for product filtering.
Run artisan command for create controller and paste the code in your own controller
php artisan make:controller FilterController
<?php
namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;
class FilterController extends Controller
{
public function all_products()
{
$all_products = Product::all();
return view('welcome',compact('all_products'));
}
public function search_products(Request $request)
{
$all_products = Product::whereBetween('price',[$request->left_value, $request->right_value])->get();
return view('search_result',compact('all_products'))->render();
}
public function sort_by(Request $request)
{
if($request->sort_by == 'lowest_price'){
$all_products = Product::orderBy('price','asc')->get();
}
if($request->sort_by == 'highest_price'){
$all_products = Product::orderBy('price','desc')->get();
}
return view('search_result',compact('all_products'))->render();
}
}
Step-8: Design custom CSS and JavaScript for the slider functionality.
We’ll be creating a custom JavaScript slider, which requires some CSS and JavaScript code to design and retrieve slider range values. If you prefer to use a different slider, feel free to skip this step. However, if you’re interested in using our custom slider, follow these instructions:
Create a CSS file named “style.css” and a JavaScript file named “script.js” inside the “public\css” and “public\js” directories, respectively. Then, paste the following code into each file.
public\css\style.css
#rangeValue {
position: relative;
text-align: center;
width: 60px;
font-size: 1.25em;
color: #fff;
background: #27a0ff;
margin-left: 15px;
border-radius: 25px;
font-weight: 500;
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.1), -5px -5px 10px #fff, inset 5px 5px 10px rgba(0, 0, 0, 0.1), inset -5px -5px 5px rgba(255, 255, 255, 0.05);
}
.middle {
position: relative;
width: 100%;
max-width: 500px;
margin-top: 10px;
display: inline-block;
}
.slider {
position: relative;
z-index: 1;
height: 10px;
margin: 0 15px;
}
.slider>.track {
position: absolute;
z-index: 1;
left: 0;
right: 0;
top: 0;
bottom: 0;
border-radius: 5px;
background-color: #b5d7f1;
}
.slider>.range {
position: absolute;
z-index: 2;
left: 25%;
right: 25%;
top: 0;
bottom: 0;
border-radius: 5px;
background-color: #27a0ff;
}
.slider>.thumb {
position: absolute;
z-index: 3;
width: 30px;
height: 30px;
background-color: #27a0ff;
border-radius: 50%;
}
.slider>.thumb.left {
left: 25%;
transform: translate(-15px, -10px);
}
.slider>.thumb.right {
right: 25%;
transform: translate(15px, -10px);
}
.range_slider {
position: absolute;
pointer-events: none;
-webkit-appearance: none;
z-index: 2;
height: 10px;
width: 100%;
opacity: 0;
}
.range_slider::-webkit-slider-thumb {
pointer-events: all;
width: 30px;
height: 30px;
border-radius: 0;
border: 0 none;
background-color: red;
cursor: pointer;
-webkit-appearance: none;
}
#multi_range {
margin: 0 auto;
background-color: #27a0ff;
border-radius: 20px;
margin-top: 20px;
text-align: center;
width: 90px;
font-weight: 500;
font-size: 1.25em;
color: #fff;
}
public\js\script.js
const input_left = document.getElementById("input_left");
const input_right = document.getElementById("input_right");
const thumb_left = document.querySelector(".slider > .thumb.left");
const thumb_right = document.querySelector(".slider > .thumb.right");
const range = document.querySelector(".slider > .range");
const set_left_value = () => {
const _this = input_left;
const [min, max] = [parseInt(_this.min), parseInt(_this.max)];
_this.value = Math.min(parseInt(_this.value), parseInt(input_right.value) - 1);
const percent = ((_this.value - min) / (max - min)) * 100;
thumb_left.style.left = percent + "%";
range.style.left = percent + "%";
};
const set_right_value = () => {
const _this = input_right;
const [min, max] = [parseInt(_this.min), parseInt(_this.max)];
_this.value = Math.max(parseInt(_this.value), parseInt(input_left.value) + 1);
const percent = ((_this.value - min) / (max - min)) * 100;
thumb_right.style.right = 100 - percent + "%";
range.style.right = 100 - percent + "%";
};
input_left.addEventListener("input", set_left_value);
input_right.addEventListener("input", set_right_value);
function left_slider(value) {
document.getElementById('left_value').innerHTML = value;
}
function right_slider(value) {
document.getElementById('right_value').innerHTML = value;
}
Step-9: Create blade file inside views
welcome.blade.php
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="{{ asset('css/style.css') }}">
<title>Laravel 9 Ajax Product Filters</title>
</head>
<body>
<div class="container">
<div class="slider-area">
@include('slider')
</div>
<div class="search-result">
@include('search_result')
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="{{ asset('js/script.js') }}"></script>
<script>
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
</script>
<script>
$(document).ready(function(e){
$('.range_slider').on('change',function(){
let left_value = $('#input_left').val();
let right_value = $('#input_right').val();
// alert(left_value+right_value);
$.ajax({
url:"{{ route('search.products') }}",
method:"GET",
data:{left_value:left_value, right_value:right_value},
success:function(res){
$('.search-result').html(res);
}
});
});
$('#sort_by').on('change',function(){
let sort_by = $('#sort_by').val();
$.ajax({
url:"{{ route('sort.by') }}",
method:"GET",
data:{sort_by:sort_by},
success:function(res){
$('.search-result').html(res);
}
});
});
})
</script>
</body>
</html>
slider.blade.php
<div class="row">
<div class="col-md-12 bg-info">
<h2 class="text-center">Laravel-9 Ajax Product Filter With Price Range Slider</h2>
</div>
<div class="col-md-5 mb-3">
<div class="middle">
<div id="multi_range">
<span id="left_value">25</span><span> ~ </span><span id="right_value">75</span>
</div>
<div class="multi-range-slider my-2">
<input type="range" id="input_left" class="range_slider" min="0" max="100" value="25" onmousemove="left_slider(this.value)">
<input type="range" id="input_right" class="range_slider" min="0" max="100" value="75" onmousemove="right_slider(this.value)">
<div class="slider">
<div class="track"></div>
<div class="range"></div>
<div class="thumb left"></div>
<div class="thumb right"></div>
</div>
</div>
</div>
</div>
<div class="col-md-5 mt-4 pt-2">
<div class="middle">
<div class="multi-range-slider my-2">
<select name="sort_by" id="sort_by" class="form-control">
<option value="">Sort By</option>
<option value="highest_price">Highest Price</option>
<option value="lowest_price">Lowest Price</option>
</select>
</div>
</div>
</div>
</div>
result.blade.php
@if($all_products->count() >=1)
<div class="row">
@foreach($all_products as $product)
<div class="col-md-3 my-2">
<div class="card" >
<img src="{{ asset('images/'.$product->image) }}" class="card-img-top" style="height:250px;">
<div class="card-body">
<h5 class="card-title">{{ $product->name }}</h5>
<p class="card-text">{{ $product->description }}</p>
<h4 class="btn btn-dark">Price ${{ $product->price }}</h4>
</div>
</div>
</div>
@endforeach
@else
<div class="col-md-12 my-5 text-center">
<h2>Nothing Found</h2>
</div>
<div>
@endif
Step-10: Test app
Everything has done, run artisan command and test your app.
php artisan serve
Thanks
Also read