Joe82
Joe82

Reputation: 1251

Vue2 - Method to highlight text with text input

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!

Upvotes: 2

Views: 4871

Answers (1)

Derek Pollard
Derek Pollard

Reputation: 7165

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!

Upvotes: 3

Related Questions