I am writing code to be able to search multiple fields within cards that pull customer data from endpoints. The first function that searches customerID works fine, but I would also like to be able to search the other fields. But I am having trouble getting it recognize multiple fields.
How can I register multiple functions inside an onkeyup field and if I am selecting the forename field in querySelector properly?
My HTML code:
<div class="container pt-3 pb-3"> <div class="form-outline" id="customer-search-bar"> <input type="search" id="filter" class="form-control" placeholder="Enter customer ID" aria-label="Search" onkeyup="searchID() && searchForename();" > </div> <div class="card-lists" id="card-lists"> <div class="row"> {% for data in raw.CustomerDataEntries %} <div class="card col-sm-12 mb-3" id="card-perim"> <div class="card-body" id="card-body"> <h5 class="card-title">Customer ID: {{ data.ExternalId }}</h5> <h5 class="card-title" name="forename">Forename: {{ data.Fields.forename }}</h5> <h5 class="card-title">Surname: {{ data.Fields.surname }}</h5> <h5 class="card-title">Postcode: {{ data.Fields.post_code }}</h5> <h5 class="card-title">Matches: {{ data.Matches }}</h5> <a href="#" class="tableButton">Details</a> <a href="#" class="tableButton">Edit</a> </div> </div> {% endfor %} </div> </div> </div>
My JavaScript code:
function searchID() { const input = document.getElementById('filter').value.toUpperCase(); const cardContainer = document.getElementById('card-lists'); console.log(cardContainer); const cards = cardContainer.getElementsByClassName('card-body'); console.log(cards); for (let i = 0; 0 < cards.length; i++){ let title = cards[i].querySelector(".card-body h5.card-title"); if(title.innerText.toUpperCase().indexOf(input) > -1){ cards[i].style.display = ""; } else { cards[i].style.display = "none"; } } } function searchForename() { const input = document.getElementById('filter').value.toUpperCase(); const cardContainer = document.getElementById('card-lists'); console.log(cardContainer); const cards = cardContainer.getElementsByClassName('card-body'); console.log(cards); for (let i = 0; 0 < cards.length; i++){ let title = cards[i].querySelector(".card-body h5[name='forename']"); if(title.innerText.toUpperCase().indexOf(input) > -1){ cards[i].style.display = ""; } else { cards[i].style.display = "none"; } } }
Advertisement
Answer
The value within the onkeyup
attribute follows JS syntax, so you should separate the statements with a semi-colon, ;
.
<input type="search" id="filter" onkeyup="searchID(); searchForename();" class="form-control" placeholder="Enter customer ID" aria-label="Search" />
However using inline event handlers is not good practice. Modern best practice is to unobtrusively bind your event handlers. In native JS you can achieve this by using addEventListener()
, like this:
let filter = document.querySelector('#filter'); filter.addEventListener('keyup', () => { searchID(); searchForename(); }); function searchID() { console.log('searchID'); } function searchForename() { console.log('searchForename'); }
<input type="search" id="filter" class="form-control" placeholder="Enter customer ID" aria-label="Search" />
The second function searchForename() still doesn’t work for me though
The main reason it doesn’t work is partly because it’s a duplication of the work being done in searchId()
, so anything displayed by searchId()
will be hidden in searchForname()
.
In addition, because you set display
state for every .card-item
in the card. This means that if the last item does not contain the searched text the entire card is hidden – even if a previous card did contain the text. To fix this hide the card to start with, then display it only if a match is found.
Here’s a working example with the search logic corrected – note that I commented out searchForename()
in the keyup
handler as it works on a subset of the same
elements as searchID
, so its use there is redundant.
let filter = document.querySelector('#filter'); filter.addEventListener('keyup', () => { searchID(); //searchForename(); }); function searchID() { const input = filter.value.toUpperCase(); const cardContainer = document.querySelector('#card-lists'); const cards = cardContainer.querySelectorAll('.card-body'); cards.forEach(card => { card.style.display = 'none'; card.querySelectorAll(".card-body h5.card-title").forEach(title => { if (title.innerText.toUpperCase().indexOf(input) > -1) { card.style.display = "block"; } }); }); } function searchForename() { const input = filter.value.toUpperCase(); const cardContainer = document.querySelector('#card-lists'); const cards = cardContainer.querySelectorAll('.card-body'); cards.forEach(card => { card.style.display = 'none'; card.querySelectorAll(".card-body h5.card-title.forename").forEach(title => { if (title.innerText.toUpperCase().indexOf(input) > -1) { card.style.display = "block"; } }); }); }
<div class="container pt-3 pb-3"> <div class="form-outline" id="customer-search-bar"> <input type="search" id="filter" class="form-control" placeholder="Enter customer ID" aria-label="Search" /> </div> <div class="card-lists" id="card-lists"> <div class="row"> <div class="card col-sm-12 mb-3"> <div class="card-body"> <h5 class="card-title">Customer ID: 123</h5> <h5 class="card-title forename">Forename: Lorem</h5> <h5 class="card-title">Surname: Ipsum</h5> <h5 class="card-title">Postcode: 90210</h5> <h5 class="card-title">Matches: Foobar</h5> <a href="#" class="tableButton">Details</a> <a href="#" class="tableButton">Edit</a> </div> </div> <div class="card col-sm-12 mb-3"> <div class="card-body"> <h5 class="card-title">Customer ID: 123</h5> <h5 class="card-title forename">Forename: Dolor</h5> <h5 class="card-title">Surname: Sit</h5> <h5 class="card-title">Postcode: 92893</h5> <h5 class="card-title">Matches: Fizzbuzz</h5> <a href="#" class="tableButton">Details</a> <a href="#" class="tableButton">Edit</a> </div> </div> </div> </div> </div> My JS code:
One last thing – note that I removed the id
attributes in the content you create in the loop. This is because repeated id
are invalid, they must contain unique values within the DOM.