I have a simple search bar and a somewhat large JSON file with name, x, y
values for each entry. Given some (x, y) values (e.g.: 1.2 0.5
) the JavaScript search bar shows cards that are within a fixed distance of 1 to that value.
This works but I need to:
- Limit the number of results to a maximum (say 10) so that there won’t be hundreds or more results shown at the same time
- Order the results by minimum distance to the (x, y) value searched
Any help will be much appreciated
const userCardTemplate = document.querySelector("[data-user-template]")
const userCardContainer = document.querySelector("[data-user-cards-container]")
const searchInput = document.querySelector("[data-search]")
let users = []
searchInput.addEventListener("input", e => {
const value = e.target.value.toLowerCase()
const xy = value.split(' ')
users.forEach(user => {
if (parseFloat(value.length) < 4) {
user.element.classList.toggle("hide", true)
} else {
var distance = Math.sqrt(
Math.pow(parseFloat(xy[0]) - parseFloat(user.x), 2) +
Math.pow(parseFloat(xy[1]) - parseFloat(user.y), 2))
const isVisible = distance <= 1
user.element.classList.toggle("hide", !isVisible)
}
})
})
fetch("https://raw.githubusercontent.com/ucc23/ucc/main/test.json")
.then(res => res.json())
.then(data => {
users = data.map(user => {
const card = userCardTemplate.content.cloneNode(true).children[0]
const header = card.querySelector("[data-header]")
const body = card.querySelector("[data-body]")
header.textContent = user.name
card.classList.add('hide')
userCardContainer.append(card)
return {
name: user.name,
x: user.x,
y: user.y,
element: card
}
})
})
.user-cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: .25rem;
margin-top: 1rem;
}
.card {
border: 1px solid black;
background-color: white;
padding: .5rem;
text-align: center;
}
.card > .header {
margin-bottom: .25rem;
}
.hide {
display: none;
}
<div class="search-wrapper">
<input type="search" id="search" data-search>
</div>
<div class="user-cards" data-user-cards-container></div>
<template data-user-template>
<div class="card">
<div class="header" data-header></div>
</div>
</template>
2
Answers
For my answer, I’m not appending the cards on the loading of the json file. This makes it load faster plus allows easy sorting later on.
I created a new array called results, this will store the matching results. On input, I empty the results and empty the html of the card container, that way the results will always be up to date. Then I append the user with it’s distance to the results array.
After that I sort the array based on the distance, then I slice the array to the first N results in this case I have it set to 10.
After that I simply loop through the results and append them to the card container element.
Also, I moved the input length if statement outside of the loop, no need to re run it for every user.
I shortened the input data a little to make it clearer: