Search code examples
vue.jsrecursionv-for

Overlapping Vue components


I've got a string like this:

"Hello World! It's me, Chelsea."

And a list of strings.

["Hello", "World", "Chelsea"]

I'd like to dynamically wrap the matching strings in Vue components. Individually, it looks like this:

<MyComponent :text="Hello"/> <MyComponent :text="World"/>! It's me, <MyComponent :text="Chelsea"/>.

The solution for this could be something like the following (thanks Ulysse BN):

<template v-for="s in string.split(/\b/)">
  <MyComponent v-if="list.includes(s)" :string="s"/>
  <span v-else>{{ s }}</span>
</template>

But we run into problems where we have multi-word strings in our list (e.g. "It's me") and more specifically, overlapping words. If we added to the list of strings "Hello World", here's what the ideal result looks like:

<MyComponent :text="Hello World"> 
  <MyComponent :text="Hello"/> 
  <MyComponent :text="World"/>!
</MyComponent>
It's me, <MyComponent :text="Chelsea"/>.

How can I achieve this functionality? I have a hunch it involves v-for and some kind of recursive function, but how I can't say.


Solution

  • I'm not sure of your use case, but maybe something like this would be suitable:

    <template v-for="item in myContent">
        <span v-if="item.type === 'string'">{{ item.content }}</span>
        <my-component v-else-if="item.type === 'component'" :text="item.content" /> 
    </template>
    
    myContent: [
        {'content': 'hello', type: 'string'},
        {'content': 'hello world', type: 'component'},
        {'content: 'world', type: 'component'},
        {'content': 'oh hello world', type: 'string'}
    ]
    

    You use computed to take the string and return it in this structure, breaking out any of the matched words.