I've been trying to make a search bar for my e-commerce website for the user to find their favorite product.
I had to use javascript to make the search bar workable but it still not working, the search bar appears but it can't be used, whenever you type in something, the page will still be the same without changing and sorting for the keyword.
My Javascript:
const search = () => {
const searchbox = document.getElementById("search-item").value.toUpperCase();
const storeitems = document.getElementById("game-list")
const product = document.querySelectorAll("pro")
const pname = storeitems.getElementsByTagName("h5")
for (var i = 0; i < pname.length; i ) {
let match = product[i].getElementsByTagName('h5')[0];
if (match) {
let textvalue = match.textContent || match.innerHTML
if (textvalue.toUpperCase().indexOf(searchbox) > -1) {
product[i].style.display = "";
} else {
product[i].style.display = "none";
}
}
}
}
<form>
<i ></i>
<input type="text" name="" id="search-item" placeholder="Search here" onkeyup="search()">
</form>
<section id="product1" >
<div id="game-list">
<div onclick="window.location.href='sproduct.html'">
<img src="img/products/f1.jpg" alt="">
<div >
<span>Developer : CD PROJEKT RED</span>
<h5>CYBERPUNK</h5>
<div >
<i ></i>
<i ></i>
<i ></i>
<i ></i>
<i ></i>
</div>
<h4>$85</h4>
</div>
<a href="#"><i ></i></a>
</div>
CodePudding user response:
The issue is in the line
const product = document.querySelectorAll("pro")
That should be const product = document.querySelectorAll(".pro")
instead.
querySelectorAll
receives an argument that must be a valid CSS selector string.
In your example i think you mean to target the element <div onclick="window.location.href='sproduct.html'">
which has a class "pro". The valid selector for that is .pro
as opposed to just pro
without the dot at the beginning.
https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll
Try this:
const search = () => {
const searchbox = document.getElementById("search-item").value.toUpperCase();
const storeitems = document.getElementById("game-list")
const product = document.querySelectorAll(".pro")
const pname = storeitems.getElementsByTagName("h5")
for (var i = 0; i < pname.length; i ) {
let match = product[i].getElementsByTagName('h5')[0];
if (match) {
let textvalue = match.textContent || match.innerHTML
if (textvalue.toUpperCase().indexOf(searchbox) > -1) {
product[i].style.display = "";
} else {
product[i].style.display = "none";
}
}
}
}
<div><form>
<i ></i>
<input type="text" name="" id="search-item" placeholder="Search here" onkeyup="search()">
</form>
<section id="product1" >
<div id="game-list">
<div onclick="window.location.href='sproduct.html'">
<img src="img/products/f1.jpg" alt="">
<div >
<span>Developer : CD PROJEKT RED</span>
<h5>CYBERPUNK</h5>
<div >
<i ></i>
<i ></i>
<i ></i>
<i ></i>
<i ></i>
</div>
<h4>$85</h4>
</div>
<a href="#"><i ></i></a>
</div>
</div>
</section>
</div>
CodePudding user response:
I know this is totally overkill from the question you asked, but I made a CodePen just to give you a possibly better way of doing what you're trying to do. At the very least, it will probably help you understand JavaScript
a little bit more. CodePen
In case you just want to see the code:
const shoppingItems = [
{
name: 'Laptop',
description: 'Dell Inspiron with Intel Core i5 processor, 8GB RAM, and 256GB SSD',
price: 499.99,
rating: 4,
keywords: ['computer', 'Intel Core i5', 'Dell']
},
{
name: 'Smartphone',
description: 'Samsung Galaxy S20 with 6.2-inch display, triple rear camera, and 5G capability',
price: 799.99,
rating: 5,
keywords: ['phone', 'Samsung', 'Galaxy S20', '5G']
},
{
name: 'TV',
description: 'LG OLED 4K TV with Dolby Vision and HDR10 support',
price: 999.99,
rating: 5,
keywords: ['television', 'LG', 'OLED', '4K']
},
{
name: 'Headphones',
description: 'Beats Solo3 wireless headphones with 40 hours of battery life and noise cancellation',
price: 199.99,
rating: 4,
keywords: ['headphones', 'Beats', 'wireless', 'noise cancellation']
},
{
name: 'Fitness Tracker',
description: 'Fitbit Charge 4 with GPS, heart rate monitor, and built-in Alexa',
price: 149.99,
rating: 3,
keywords: ['fitness tracker', 'Fitbit', 'GPS', 'heart rate monitor']
}
]
// Select the template element and the container for search results
const itemTemplate = document.querySelector('[data-item="template"]'),
resultsContainer = document.querySelector('#search-results'),
searchInput = document.querySelector('#search-input')
// Declare variables to store the search buffer timeout and the closest above and below items
let searchBuffer,
closestAbove,
closestBelow
// Add an event listener to the search input element that listens for keyup events
searchInput.addEventListener('keyup', (e) => {
// Clear the search buffer timeout
clearTimeout(searchBuffer)
// Set a new timeout for the search buffer
searchBuffer = setTimeout(() => {
// Clear the search results container
resultsContainer.innerHTML = ''
// Get the search value from the search input element
const searchValue = searchInput.value
// Reset the closest above and closest below items
closestAbove = { price: Infinity }
closestBelow = { price: -Infinity }
// Loop through each shopping item
shoppingItems.forEach(shoppingItem => {
// Set the display flag to false
let display = false
// Check if the search value is in the name or description of the item
if (
shoppingItem.name.toLowerCase().includes(searchValue.toLowerCase())
||
shoppingItem.description.toLowerCase().includes(searchValue.toLowerCase())
) display = true
// If the display is still false, check if the search value is in any of the item's keywords
if (!display) {
shoppingItem.keywords.forEach(keyword => {
if (keyword.toLowerCase().includes(searchValue.toLowerCase())) display = true
})
}
// If the display is still false, check if the search value is a price
if (!display) {
// If the item's price is greater than or equal to the search value and less than the current closest above item, set the closest above item to this item
if (
shoppingItem.price >= Number(searchValue)
&&
shoppingItem.price < closestAbove.price
) closestAbove = shoppingItem
// If the item's price is less than or equal to the search value and greater than the current closest below item, set the closest below item to this item
if (
shoppingItem.price <= Number(searchValue)
&&
shoppingItem.price > closestBelow.price
) closestBelow = shoppingItem
}
// If the search value is an empty string, don't display the item
if (searchValue === '') display = false
// If the display flag is true, display the item
if (display) displayItem(shoppingItem)
})
// If the closest above item has a price less than Infinity or the closest below item has a price greater than -Infinity, display it
if (
closestAbove.price < Infinity
||
closestBelow.price > -Infinity
) displayItem(closestAbove)
}, 500)
})
/**
* Displays a shopping item in the search results container
* @param {Object} item - The shopping item to display
* @param {string} item.name - The name of the item
* @param {string} item.description - The description of the item
* @param {number} item.price - The price of the item
* @param {number} item.rating - The rating of the item (out of 5)
*/
function displayItem(item) {
// Destructure the item object and create a few other variables
const { name, description, price, rating } = item,
starsRating = [],
randomHue = Math.floor(Math.random() * 360),
randomHsl = `hsl(${randomHue} 75% 40%)`
// Create an array of filled or empty starts for the rating
for (let i = 0; i < 5; i ) {
rating <= i
?
starsRating.push('☆')
:
starsRating.push('★')
}
// Clone the item template element and select some of its child elements
const searchedItem = itemTemplate.content.cloneNode(true),
nameField = searchedItem.querySelector('[data-item="name"]'),
priceField = searchedItem.querySelector('[data-item="price"]'),
ratingField = searchedItem.querySelector('[data-item="rating"]'),
descriptionField = searchedItem.querySelector('[data-item="description"]'),
hr = searchedItem.querySelector('hr')
// Set the box shadow of the searchItem element to a random hue
descriptionField.parentNode.style.boxShadow = `0 0.25rem 2rem hsl(0 0% 0% / 0.15), 0 0 5rem hsl(${randomHue} 100% 50% / 0.15)`
// Set the inner text and color of the name field to the item's name and a random hue
nameField.innerText = name
nameField.style.color = randomHsl
// Set the inner text of the price field to the item's price
priceField.innerText = `$${price}`
// Set the inner text and color of the rating field to the rating array and a random hue, and set the text shadow of the field to a random hue
ratingField.innerText = starsRating.join('')
ratingField.style.color = randomHsl
ratingField.style.textShadow = `0 0 0.25rem hsl(${randomHue} 100% 50% / 0.4)`
// Set the inner text of the description field to the item's description
descriptionField.innerText = description
// Set the border color of the hr element to a random hue
hr.style.borderColor = randomHsl
// Append the cloned and modified item template element to the search results container
resultsContainer.appendChild(searchedItem)
}
*,
html,
body {
margin: 0;
padding: 0;
box-sizing: border-box;
position: relative;
font-family: sans-serif;
}
.container {
padding: 2rem;
background-color: lightgray;
min-height: 100vh;
display: flex;
flex-direction: column;
gap: 1rem;
}
input {
padding: 0.5rem;
border-radius: 0.5rem;
border: none;
font-size: 1rem;
}
input::placeholder {
color: gray;
}
ul {
list-style-type: none;
display: grid;
grid-auto-flow: row;
gap: 1rem;
}
li {
background-color: white;
padding: 1rem;
display: grid;
grid-auto-flow: row;
gap: 1.25rem;
border-radius: 1rem;
}
.item-top-container {
display: grid;
grid-auto-flow: row;
gap: 0.25rem;
}
.rating-price-container {
display: flex;
align-items: center;
gap: 0.5rem;
}
[data-item="price"],
[data-item="rating"] {
font-size: 0.9rem;
}
hr {
border-width: 1px;
border-style: solid;
border-radius: 1rem;
}
<div class='container'>
<input id='search-input' type="text" placeholder="Search our store" />
<h2>Results</h2>
<ul id="search-results"></ul>
<template data-item="template">
<li data-item="container">
<div class='item-top-container'>
<h3 data-item="name"></h3>
<div class='rating-price-container'>
<p data-item="price"></p>
<p data-item="rating"></p>
</div>
</div>
<hr>
<p data-item="description"></p>
</li>
</template>
</div>