16

I need help writing a text highlight filter using vuejs. The idea is to loop through a given array of words and if there is a match, apply a span with a class to that word. The problem I have is that, I can't seem to return data with html formatting with vuejs. Any ideas will be highly appreciated. I am really stuck with this.

Vue.filter('highlight', function(words, query){
    //loop through **words** and if there is a match in **query**
   //apply a <span> with some style
   //At the end return formatted string to html page
})
1
  • markjs.io Commented Jun 15, 2016 at 16:06

4 Answers 4

19

HTML interpolations {{{ foo }}} have been removed in favor of the v-html directive in vuejs2.X, thus from version 2.x, Vue.js allows for raw JavaScript templating (React-style) in addition to HTML templating.
@jeff's answer is correct but for vuejs 1.x versions, but in case {{{}}} didn't work for you guys or if you want to evaluate the tags in the HTML, and from a trusted source, example, if you want to add a <strong></strong> tag, then you need to use v-html, the v-html to ask Vue to evaluate the string as HTML:

<span v-html="$options.filters.highlight(item, val)">{{ item }}</span>

highlight filter:

Vue.filter('highlight', function(word, query){
  var check = new RegExp(query, "ig");
  return word.toString().replace(check, function(matchedText,a,b){
      return ('<strong>' + matchedText + '</strong>');
  });
});

or you can use @Thomas Ferro's filter

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

2 Comments

A slightly different version that let you use multiple queries (comma separated): /** * * @param { String } words * @param { String } query */ export const highlight = (words, query) => { var check = new RegExp(query.split(",").join("|"), "ig"); return words.toString().replace( check, (matchedText, a, b) => { return `<strong>${matchedText}</strong>` } ) }
good sample, thanks I used this. It would be nice if you can add a warning of the potential security risk when using v-html
13

As Jeff just said, the basic mustaches interprets the data as plain text.

You can add your span by replacing the query with the String.replace() method.

Here's a basic example: https://jsfiddle.net/0jew7LLz/

Vue.filter('highlight', function(words, query) {
    return words.replace(query, '<span class="highlight">' + query + '</span>')
});

4 Comments

This is risky to use if words is not sanitized.
is it possible when I call vue version 2?
I don't know if you can declare global filters, like in the example, but the scoped filters are still available : vuejs.org/v2/guide/filters.html
string.replace will replace one segment only. Regex may be necessary to highlight all match text.
5

The idea is to use split and keep the words that the regex matches.

Here is a user safe component that escapes html and highlights a regexp that searches for multiple words:

Vue.component('child', {
  props: ['msg', 'search', 'effect'],
  template: '<span><span v-for="(s, i) in parsedMsg" v-bind:class="getClass(i%2)">{{s}}</span></span>',
  methods: {
    getClass: function(i) {
      var myClass = {};
      myClass[this.effect] = !!i;
      return myClass;
    },
  },
  computed: {
    parsedSearch : function () {
        return '(' + this.search.trim().replace(/ +/g, '|') + ')';
    },
    parsedMsg: function() {
        return this.msg.split(
        new RegExp(this.parsedSearch , 'gi'));
    }
  }
})

new Vue({
  el: '#app',
  }
  // ...
})

Usage example:

<div id="app">
  <child msg="My life so good and awesome, is'nt it great?" search="   life   is   good  " effect='highlight'> </child>
</div>

jsfiddle:

https://jsfiddle.net/50xvqatm/

Comments

2

You need to use {{{ foo | highlight }}} with 3 braces, not with 2 {{}}. Two braces escapes HTML.

3 Comments

I didn't know this was possible.. learned something new.. appreciated.
Hi, but what if you still want to escape the string, just not the highlight?
Cette réponse n'est pas valide chez moi en version 2.X.

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.