Dynamically Compile <router-link />

I have been developing project with some old API, a part from which is that entire content returned form server contain <a> link, I have been able to convert these <a> to <router-link> in string format with RegEx, but when insert into html using v-html, things not going right, see example below:

in content.vue file:

<template>
  <div v-html="transformed"></div>
</template>

<script>
import { transformer } from './../filters'

export default {
  name: 'ContentVue',
  props: {
    text: {
      type: String,
      default: ''
    }
  },

  computed: {
    transformed () {
      return transformer(this.text) '
      //something contain one or more: <router-link to="/app/user/a">aaa</router-link>'
    }
  }

}
</script>

the dynamically outputted content in browser is just:

<router-link to="/user/usera">usera</router-link>

or I have change the template as

<template>
  <div >{{transformed}}</div>
</template> 

and make transformed a computed value but not work. then my Vue-Router setup is completely broken :tired_face:


what I expected is it will compile" <router-link> as <a href="/user/usera">usera</a>

Anybody any suggestion how to get this work?

this will not work with v-html - you have to create a small dynamic component. For that, your computed prop should return an object of component options with that string as its template:

computed: {
  transformed() {
    return {
      template: transformer(...),
      props: this.$options.props
    }
  }
}

Usage in the template:

<component v-bind:is="transformed" v-bind="$props"/>

The stuff with $props makes sure that this dynamic component receives the same props as the parent, so you can access those if need be. If it should also access the data, you would have to pass that as an extra prop, or add it in the dynamic options object.

2 Likes

This works totally well, Thanks
BTW, I am relative new to Vue.js, and I have tried to find the v-bind:is and v-bind="" in API and Docs but no result, is there any documentation about this approach?

Here and here

I think we should document it in the API’s List of special attributes, though. I opened an issue.

Here

looks like a good solution, but I am confused a bit here. Where does transformer come from ? Is it custom filter or something like that ?

That’s really unimportant for the issue itself. It some additional stuff that OK uses on the template for whatever reason.

The solution works fine without it.

Hi, here is the codepen I made long time ago based on this thread, still works totally fine, hope it can help.

The transformer() method is literally a transformer(a helper method), which in original project helping transform the text, in the codepen provided above, just return the router-link in text for demostration purpose

Vue.component('dynamic-link', {
  template: `<component v-bind:is="transformed" /></component>`,

  data () {
    return {
      text: `
      <router-link to="/foo">
        <button class="button is-link is-outlined">
          Go to Foo (compiled router-link)
        </button>
      </router-link>
      `
    }
  },
  
  computed: {
    transformed () {
      return { template: this.text }
    }
  }
});

2 Likes

Thank you for this example it was super helpful!

I was spending hours to find a solution for this problem

I am having the same problem…most of the template code come from ajax call … and now the SPA recognize the “vue syntax” from the template.

I have found this project

which is a great tool :+1:

Note that for this to work, you’ll need to make sure you’re using the build of Vue core that includes the runtime compiler.

In your vue.config.js (create one if it doesn’t exist in the root already):

module.exports = {
  runtimeCompiler: true,
}

more info: https://cli.vuejs.org/config/#runtimecompiler