4

I have a list of words, such as:

["Foo","Bar"]

When presented with a string, I'd like to dynamically replace words found in the list with components. Given a string like this:

"Foo lorem ipsum dolor Bar."

The result would be:

<MyComponent :text="Foo"/> lorem ipsum dolor <MyComponent :text="Bar"/>.

What's the best way to achieve this?

2 Answers 2

1

Here's my approach:

Vue.component('my-component', {
  props: ['word'],
  template: '<span class="my-component">{{word}}</span>'
})
new Vue({
  el: '#app',
  data() {
    return {
      text: 'Foo is the new Bar.',
      filters: new Set(['Foo', 'Bar'])
    }
  },
  computed: {
    tokens() {
      return this.text.match(/(?:\b|^).+?(?:\b|$)/g)
    }
  }
})
.my-component {
  color: #0095ff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <template v-for="token in tokens">
    <my-component v-if="filters.has(token)" :word="token"></my-component>
    <template v-else>{{ token }}</template>
   </template>
</div>

The idea is quite straightforward:

  1. split the desired string into tokens
  2. for each token, verify if it is in word list:
    • if so, render it with your component
    • otherwise, render it as default

This will do literally what you want :)

NOTE: the use of template helps having a clean HTML output, without useless div or span elements.

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

3 Comments

Thank you! This is exactly what I'm looking for. One quick addition--how would you recommend handling recursive cases, such as ['Foo', "Foo Bar', 'Bar'] => "Foo Bar is new" ?
The issue is totally different in that case. You could maybe take advantage of string.includes and remove any substring that has already been processed?
Thank you, I'll consider that.
0

I think v-for is the only thing needed for this.

Vue.component('mycomponent', {
  props: ['word'],
  template: '<div> Word is {{word}} </div>'
})


var vm = new Vue({
  el: '#app',
  data: function(){
    return{
        text: 'Foo lorem ipsum dolor Bar',
      selectedWords: ['Foo', 'Bar']
    }
  },
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.0/vue.js"></script>

<div id="app" >
  <div v-for="item in text.split(' ')">
    <div v-if="selectedWords.includes(item)">
      <mycomponent
            :key="item"
            :word="item">
      </mycomponent>
    </div>
    <div v-else>
      {{item}}
    </div>
  </div>
</div>

jsfiddle

Explanation

I've passed word as a prop to mycomponent. Then used the shorthand for v-bind: which is : to bind item to word

Disclaimer: I also am learning Vue XD

3 Comments

Although v-for is the right direction, I don't think that would give me the behavior (e.g. "lorem ipsum dolor" unwrapped) I'm looking for.
Ah yes you're right Jasper, sorry when I read the question I saw 'the list' and assumed there was only one
No worries at all!

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.