Guillaume
Guillaume

Reputation: 135

Change the style of a substring in a v-for loop

I am trying to change the color of some hardcoded substrings that can be present in a v-for loop used to populate a table.

My loop is the following:

              <tr v-for="(src, index) in contentArray.content" :key="src.id">
                <td class="myclass1" >{{ src.something1 }}</td>
                <td class="myclass2">{{ src.string }}</td>
              </tr>

Let's say that I want to apply a specific color on a substring of src.string.

For instance if src.string is:

This is a test

I want to be able to apply a color on the word 'test'.

The substring that I want to color will not be present in every string of the loop.

I have a subset of multiple hardcoded substrings that I want to color.

How can I do that ?

I tried to play with another v-for loop with the split method, or with a v-bind:class but I can figure how to do this ...

Thanks

Upvotes: 0

Views: 411

Answers (3)

tony19
tony19

Reputation: 138656

You could split the string in the template, and conditionally render a span only for each matching word:

<template v-for="w in src.string.split(/\s+/)">
  <span class="keyword" v-if="w === searchWord">{{w}} </span>
  <template v-else>{{w}} </template>
</template>

demo 1

Note this solution limits the searchability of phrases (it searches only for single words).

Alternatively, you could use a computed property that wraps only the target word(s) with a span:

  1. Declare a computed property (called "computedContent") that preprocesses the string properties of contentArray.content, wrapping all target words with <span class="keyword">:

    export default {
      computed: {
        computedContent() {
          const searchWord = this.searchWord.trim()
          if (!searchWord) return this.contentArray.content
    
          return this.contentArray.content.map(x => ({
            ...x,
            string: x.string.replace(new RegExp(searchWord, 'ig'), w => `<span class="keyword">${w}</span>`)
          }))
        }
      }
    }
    
  2. Update the template to use this computed property instead:

    <tr v-for="(src, index) in computedContent" :key="src.id">
    
  3. Use the v-html directive to bind the td's innerHTML to src.string:

    <td class="myclass2" v-html="src.string"></td>
    
  4. In your component's <style> block, select .keyword to style it:

    <style>
    .keyword {
      font-family: Monaco, sans-serif;
      font-weight: bold;
      color: blue;
    }
    </style>
    

demo 2

Upvotes: 1

Daniel Adegoke
Daniel Adegoke

Reputation: 199

<tr v-for="(src, index) in contentArray.content" :key="src.id">
  <td class="myclass1" >{{ src.something1 }}</td>
  <td class="myclass2">
{{ src.string.includes('test') ? src.string.replace('test', `${<span :class={color: 'yourColor'}></span>}`) : src.string }}
  </td>
</tr>

You can check for the word you want to change with .includes() and replace that word with .replace() with the html tag and class you want

Upvotes: 1

Boussadjra Brahim
Boussadjra Brahim

Reputation: 1

You could split the string as you said then bind the class conditionally :

<td class="myclass2">
   <span v-for="substr in src.string.split(' ')" :class="{'someClass':substr==='test'}">
      {{substr}}
   </span>
</td>

Upvotes: 0

Related Questions