2

I'm trying to highlight a text when it matches the text entered in a text input.

So if I have this data

data: function() {
  return {
    names:['John', 'Johan', 'Diego', 'Edson']
    searchFilter:''
  }
}

And this html:

<input type="text" v-model="searchFilter">
<div v-for="b in names">
   <p v-html="highlight(b)"></p>
</div>

If I type "Joh" in the input, I would like to get in my html:

John

Johan

Diego

Edson

<div>
  <p><strong>Joh</strong>n</p>
  <p><strong>Joh</strong>an</p>
  <p>Diego</p>
  <p>Edson</p>
</div>

So far, I have written this method, but it highlights all the word, not just the typed characters.

methods: {
  highlight(itemToHighlight) {
    if(!this.searchFilter) {
      return itemToHighlight;
    }
    return itemToHighlight.replace(new RegExp(this.searchFilter, "ig"), match => {
      return '<strong">' + match + '</strong>';
    });
  }
}

Any advice would be great. Thanks!

1 Answer 1

3

Rough proof of concept

You could do something like this:

methods: {
  highlight(itemToHighlight) {
    if(!this.searchFilter) {
      return itemToHighlight;
    }
    return itemToHighlight.replace(new RegExp(this.searchFilter, "ig"), match => {
      return '<strong">' + this.searchFilter + '</strong>' + (match.replace(this.searchFilter, ''));
    });
  }
}

Essentially, the idea being that you are using the matching search term as a base, then getting the portion that doesn't match by replacing the matched string with nothing ('').

Please note, this wasn't tested, but more of a proof of concept for you. It most likely works.

A working pure JavaScript implementation

function nameMatcher(names, searchTerm) { 
  return names.reduce((all, current) => {
    let reggie = new RegExp(searchTerm, "ig");
    let found = current.search(reggie) !== -1;
    all.push(!found ? current : current.replace(reggie, '<b>' + searchTerm + '</b>'));
    return all;
  }, []);
}

let allNames = ['John', 'Johan', 'Deon', 'Ripvan'];
let searchTerm = 'Joh';

console.log(nameMatcher(allNames, searchTerm));

By running the example, you will see that the function nameMatcher correctly replaces the properly matched string within each positive match with the search term surrounded with a <b> element.

A working Vue Implementation

new Vue({
  el: ".vue",
  data() {
    return {
      names: ['John', 'Johan', 'Deon', 'Derek', 'Alex', 'Alejandro'],
      searchTerm: ''
    };
  },
  methods: {
    matchName(current) {
      let reggie = new RegExp(this.searchTerm, "ig");
      let found = current.search(reggie) !== -1;
      return !found ? current : current.replace(reggie, '<b>' + this.searchTerm + '</b>');
    }
  }
  
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div class="container vue">
  <input v-model="searchTerm" placeholder="Start typing here...">
  <div v-for="(name, key) in names"> 
    <div v-html="matchName(name)"></div>
  </div>
</div>

Let me know if you have any questions! Hope this helps!

Sign up to request clarification or add additional context in comments.

3 Comments

The first "proof of concept" I couldn't make it work, but the last example works like a charm!
@Joe82 glad it worked for you! I generally try to show my line of thinking in these answers so others who come here can get a feel of where I was coming from
Yep, thanks a lot for that. I was also trying to make a fiddle in order to make it work, but you were faster :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.