Home > Enterprise >  Marking searched results with JavaScript
Marking searched results with JavaScript

Time:01-30

I made a search bar that takes everything typed into it and checks if the json file has the name, author or category that matches to it.

How could I make it so that everything typed into the search bar gets highlighted in the part where it displays matched results?

Here is a picture of the search bar for example. I typed in FPS and it found a category with FPS in it. I would want the fps part to be highlighted.

enter image description here

How I made the search bar work:

const search = document.getElementById("search");
const matchList = document.getElementById("match-list");

const searchStates = async searchText => {
  const res = await fetch("firebase link");
  const states = await res.json();
  const listaInformacija2 = Object.values(states)
 
  let matches = listaInformacija2.filter(state => {
    const regex = RegExp(`^${searchText}`, "gi");
    return state.autor.match(regex) || state.naziv.match(regex) || state.kategorija.match(regex);
  });

  if(searchText.length === 0) {
    matches = []
    matchList.innerHTML = "";
  }
  outputHtml(matches);
};

const outputHtml = matches => {
  if(matches.length > 0){
    const html = matches.map(match => `
    <a href=kurs.html?id=${match.id} id="searchedLink">
    <div  id="allCourses">  
        <h4>${match.naziv}</h4>
        <p>Kategorija: ${match.kategorija}</p>
        <p>Autor: ${match.autor}</p>
    </div>
    </a>
    `).join("");
    matchList.innerHTML = html;
  }
}
search.addEventListener("input", () => searchStates(search.value));

CodePudding user response:

You can add a specific span element to the highlighted text dynamically, I would also avoid making a Firebase call each search, as it would cost a lot of money if the app scale, here is what I got:

const FIREBASE_URL = '<your firebase url>';
const $search = document.getElementById('search');
const $matchList = document.getElementById('match-list');
const data = {};

function escape(str) {
  return str.replace(/[.* ?^${}()|[\]\\]/g, '\\$&');
}

function search(query) {
  if (!query) return [];
  if (!data.statesList) return [];

  const matches = data.statesList.filter(state => query.test(state.autor) || query.test(state.naziv) || query.test(state.kategorija));

  return matches;
}

function render(matches, originalValue, query) {
  if (!matches.length) {
    $matchList.innerHTML = '';
    return;
  }

  const html = matches
    .map(match => {
      const replacer = `<span >${originalValue}</span>`;
      return `
        <a href=kurs.html?id=${match.id} >
          <div  >  
            <h4>${match.naziv.replace(query, replacer)}</h4>
            <p>Kategorija: ${match.kategorija.replace(query, replacer)}</p>
            <p>Autor: ${match.autor.replace(query, replacer)}</p>
          </div>
        </a>`;
    })
    .join('');

    $matchList.innerHTML = html;
}

function inputHandler(event) {
    const { value } = event.target;
    let query;

    if (!value) query = null;
    else query = new RegExp(escape(value), 'i');

    const matches = search(query);

    render(matches, value, query);
}

async function init() {
  const response = await fetch(FIREBASE_URL);
  data.states = await response.json();
  data.statesList = Object.values(data.states);
  $search.addEventListener('input', inputHandler);
}

init().catch(console.error);

And your CSS could look like this:

.search-match {
  background-color: #e0d392f0;
}
  •  Tags:  
  • Related