0

I'm implementing a search highlight feature. I've been able to use regex to find all instances of a particular keyword in my table, and highlight it. What I'm trying to do now is be able to jump to the next/prev highlight word using Enter and Shift+Enter resp. Here's what I'm currently doing:

highlightSearchKeyword () {
      const reviews = document.querySelectorAll('span[data-v-071a96ec=""]')
      const formattedKeyword = this.searchKeyWord.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
      let count = 0
      reviews.forEach(rev => {
        const substring = new RegExp(formattedKeyword, 'gi')
        let description = rev.innerText
        if (formattedKeyword !== '') {
          try {
            count += description.match(substring || []).length
          } catch (error) {
            count += 0
          }
        }
        description = description.replace(substring, match => `<span class="highlight" id="search-${some-id}">${match}</span>`)
        rev.innerHTML = description
      })
      this.highlightedWordCount = count
    }

As you can see, I'm replacing each match with a string that surrounds the original match word by a <span> tag. I want to give each instance of a match an id, so that I can do something like:

const elem = document.querySelector(`#search-{some-id}`)
elem.scrollIntoView()

If someone could help me out with this that'd be great.

Omar Siddiqui
  • 1,625
  • 5
  • 18

1 Answers1

0

You could use the index that forEach passes you:

highlightSearchKeyword () {
  const reviews = document.querySelectorAll('span[data-v-071a96ec=""]')
  const formattedKeyword = this.searchKeyWord.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
  let count = 0
  reviews.forEach((rev, index) => { // *** Added `index` parameter
    const substring = new RegExp(formattedKeyword, 'gi')
    let description = rev.innerText
    if (formattedKeyword !== '') {
      try {
        count += description.match(substring || []).length
      } catch (error) {
        count += 0
      }
    }
    // *** −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−vvvvv
    description = description.replace(substring, match => `<span class="highlight" id="search-${index}">${match}</span>`)
    rev.innerHTML = description
  })
  this.highlightedWordCount = count
}

Or if you need to do this more than once and may end up with the same IDs that way, have a variable you increment as necessary;

// Somewhere in code that `highlightSearchKeyword` closes over:
let nextId = 1;

// Then:
highlightSearchKeyword () {
  const reviews = document.querySelectorAll('span[data-v-071a96ec=""]')
  const formattedKeyword = this.searchKeyWord.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
  let count = 0
  reviews.forEach(rev => {
    const substring = new RegExp(formattedKeyword, 'gi')
    let description = rev.innerText
    if (formattedKeyword !== '') {
      try {
        count += description.match(substring || []).length
      } catch (error) {
        count += 0
      }
    }
    // *** −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−vvvvvvvv
    description = description.replace(substring, match => `<span class="highlight" id="search-${nextId++}">${match}</span>`)
    rev.innerHTML = description
  })
  this.highlightedWordCount = count
}

Side note -- Re: new RegExp(formattedKeyword, 'gi'), two things:

  • If formattedKeyword has any characters in it that have special meaning to regular expressions (like () or $ or ^ or...), the regular expression won't be what you expect it to be. This question's answers have various implementations of an "escape" function for regular expressions you could use to avoid that concern.
  • Note that it will do a substring match (it'll find nan in banana, for instance). If that's what you want, great, but if not add \b at the beginning and end.
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thank you! Your second suggestion worked perfectly. I'll keep in mind the formattedKeyword advice. For now it is working as I need it to, but if I ever need to change the behaviour of the search in the future, this will definitely come in handy! :D – Omar Siddiqui Apr 02 '21 at 12:45