Select Page

Vue Replace Text With a Component With Props

For example, in Vue application, you have an HTML content with some placeholders that you want to be replaced with components. The placeholder in the text could be [BuyHere], and you want a component BuyButton.vue in that place when showing the page to the website visitor. This can be accomplished by using Vue’s dynamic components.

Create a src/components/BuyButton.vue. This piece of code represents a very minimal button. However, we have introduced some props here to make it a little bit more complex.

<template>

    <input type="button" :value="label">

</template>
<script>
  
    export default {
        name: 'BuyButton',
        props: ['label']
    }

</script>

Then let’s have a component that renders the HTML content src/components/ContentView.vue:

<template>

    <component v-bind:is="processedHtml"></component>

</template>
<script>

    import BuyButton from './BuyButton';

    export default {
        name: 'ContentView',
        components: {
            BuyButton
        },        
        data () {
            return {
                html: '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>[BuyHere]<p>Donec tellus arcu, rhoncus eget leo sit amet, blandit aliquam sapien.</p><p>Aenean leo ligula, ultricies non nisi non, laoreet mattis arcu.</p>',
            }
        },
        computed: {

            processedHtml () {
                let html = this.html.replace('[BuyHere]', '<buy-button label="Buy Here!"></buy-button>');
                return {
                    template: '<div>' + html + '</div>'
                }

            }
        }
    }

</script>

In the template section, we have a <component> that will get a dynamic content provided by processedHtml, where we replace the placeholder with a string that contains the component HTML. It is important to return an HTML code that has one single root element. Otherwise, you will get an error.

Enable Runtime Compiler in Vue

If you now try to run it, you will most likely get an error: [Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build. This happens in dev environment, and it is easy to fix. In Vue settings, there is an option to switch on the runtime compiler. If you don’t already have a file vue.config.js in project root next to the file package.json, create it and add a couple of lines.

module.exports = {
    runtimeCompiler: true
}

Now it should work, but the next error might be: [Vue warn]: Unknown custom element: <buy-button> – did you register the component correctly? For recursive components, make sure to provide the “name” option. To fix this issue, you can explicitly set the component in ContentView.vue. Add following lines to the import part under the BuyButton import:

import BuyButton from "./BuyButton";
import Vue from 'vue';
Vue.component('buy-button', BuyButton);

Now you should be able to run the application without problems and see the button in the middle of the lorem ipsum text.

How to Pass Properties to the Dynamic Component?

Let’s add a label data attribute in our ContentView component to dynamically pass the label of the button as a property for BuyButton.

data () {
    return {
        html: '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>[BuyHere]<p>Donec tellus arcu, rhoncus eget leo sit amet, blandit aliquam sapien.</p><p>Aenean leo ligula, ultricies non nisi non, laoreet mattis arcu.</p>',
        label: 'Buy Here! -10% Off',
    }
},

Then we will modify our computed processedHtml method:

let html = this.html.replace('[BuyHere]', '<buy-button :label="label"></buy-button>');

This would make sense, but you will most likely get an error: [Vue warn]: Property or method “label” is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. To overcome this last problem, we can pass the label property to the dynamic component by passing it as a default value along with the props in the object with the template itself:

computed: {

    processedHtml () {
        let html = this.html.replace('[BuyHere]', '<buy-button :label="label"></buy-button>');
        return {
            template: '<div>' + html + '</div>',
            props: {
                label: {
                    type: null,
                    default: () => { return this.label }
                },
            }
        }
    }
}

Did you find this tutorial helpful? Please share:

Photo by Ash Edmonds on Unsplash

 

Subscribe to newsletter

We will never send you any marketing material