Vue - Render an element out of string

vue render function pass props
vue render html
vue jsx slots
vue.js template example
vue function
vnode vue
javascript render
v-bind' directives require an attribute value

I would like to create a vue element from a string from my database.

In this case, it should be a message with a smiley emoji. I actually save it like: Some text with Emoji: :santa::skin-tone-3:, and replace all valid string between '::' with the <Emoji emoji=':santa::skin-tone-3:' :size='16' />

<template>
  <span class=message v-html=convertedMessage></div>
</template>

<script>
  import { Emoji } from 'emoji-mart-vue'

  export default {
    components: {
      Emoji
    },
    computed:{
      convertedMessage(){
        return "Some text with Emoji: "+"<Emoji emoji=':santa::skin-tone-3:' :size='16' />"
      }
    }
  }
</script>

But instead of the rendered element which should be something like:

<span data-v-7f853594="" style="display: inline-block; width: 32px; height: 32px; background-image: url(&quot;https://unpkg.com/emoji-datasource-apple@4.0.4/img/apple/sheets/64.png&quot;); background-size: 5200%; background-position: 15.6863% 41.1765%;"></span>

I only get:

<emoji emoji=":santa::skin-tone-3:" :size="16"></emoji>

What is the best possibility to render this Element like intended?

What i figured out now:

convertedMessage(){
    let el = Vue.compile("<Emoji emoji=':santa::skin-tone-3:' :size='16' />")
    el = new Vue({
        components: {
            Emoji
        },
        render: el.render,
        staticRenderFns: el.staticRenderFns
    }).$mount()
    return "Some text with Emoji: "+el.$el.innerHTML
}

Maybe there is still a better solution to handle this?

Render Functions & JSX, I have a list component where there's an option for columns so they can be formatted. This format is the “inside” a JavaScript funtion stored as a  render: function (createElement) { return createElement('h1', this.blogTitle) } And in both cases, Vue automatically keeps the page updated, even when blogTitle changes. The Virtual DOM. Vue accomplishes this by building a virtual DOM to keep track of the changes it needs to make to the real DOM. Taking a closer look at this line:

Here are some much easier ways to do what you generally want. If you give more specifics, your right direction may be a strategy pattern before one of these solutions, but one of these solutions is probably what you want:

1) Vue lets you dynamically define components right out of the box, so this single line:

<component v-for="(component, index) in components" :key="'component'+index" :is="component.name" v-bind="component.props" />

...would draw a bunch of components in an array of objects like this (for example): {name: 'myComponentName', props: {foo: 1, bar: 'baz'}}.

2) Vue lets you inject HTML into components by simply adding v-html="variable"

For example, here is a component that creates dynamic SVG icons, where the contents of the SVG is dynamically injected from JavaScript variables...

<template>
  <svg xmlns="http://www.w3.org/2000/svg"
    :width="width"
    :height="height"
    viewBox="0 0 18 18"
    :aria-labelledby="name"
    role="presentation"
  >
    <title :id="name" lang="en">{{name}} icon</title>
    <g :fill="color" v-html="path">
    </g>
  </svg>
</template>

<script>
import icons from '../common/icons'
export default {
  props: {
    name: {
      type: String,
      default: 'box'
    },
    width: {
      type: [Number, String],
      default: 18
    },
    height: {
      type: [Number, String],
      default: 18
    },
    color: {
      type: String,
      default: 'currentColor'
    }
  },
  data () {
    return {
      path: icons[this.name]
    }
  },
  created () {
    console.log(icons)
  }
}
</script>

<style scoped>
  svg {
    display: inline-block;
    vertical-align: baseline;
    margin-bottom: -2px;
  }
</style>

3) Vue lets you dynamically define your component template through this.$options.template:

export default {
  props: ['name', 'props'],
  template:  '',
  created(){
    this.$options.template = `<component :is="name" ${props.join(' ')} ></component>`
  },
}

4) Vue lets you define a render function, so proxy components or other advanced shenanigans are trivial:

Vue.component('component-proxy', {
  props: {
    name: {
      type: String,
      required: true
    },
    props: {
      type: Object,
      default: () => {}
    }
  },
  render(h) {
    // Note the h function can render anything, like h('div') works too.
    // the JS object that follows can contain anything like on, class, or more elements
    return h(this.name, {
      attrs: this.props
    });
  }
});

A smart genius wrote a jsbin for this here: http://jsbin.com/fifatod/5/edit?html,js,output

5) Vue allows you to create components with Vue.extend or even passing in raw JavaScript objects into a page or apps components section, like this, which creates a component named "foo" from a simple string for the template and an array for props, you could also extend the data, created, on, etc. the same way using the JS object alone:

new Vue({
  el: '#app',
  data: {
    foo: 'bar',
    props: {a: 'a', b: 'b'}
  },
  components: {
    foo: {
      template: '<p>{{ a }} {{ b }}</p>',
      props: ['a', 'b']
    }
  }
})

Template Syntax, Perhaps, for some reason you need to render raw HTML in your Vue components​. a good reason for needing to insert raw HTML stored as strings into the DOM. Anyway, it turns out that Vue provides us with a nice little directive that can the same way, except it only sets the text content of an element. Similar to v-else, a v-else-if element must immediately follow a v-if or a v-else-if element. Controlling Reusable Elements with key. Vue tries to render elements as efficiently as possible, often re-using them instead of rendering from scratch. Beyond helping make Vue very fast, this can have some useful advantages.

v-html only render plain HTML, see https://vuejs.org/v2/guide/syntax.html#Raw-HTML

In your case you should probably take a look at render functions and JSX. I'm not an expert but it seems that some people are acheiving what you want with the dangerouslySetInnerHTML JSX function. Take a look at this thread : How do I convert a string to jsx?

I know sometimes we have no choice but if you can I think the best solution could be to avoid generating the template from the backend as it breaks separation of concern (and also, probably, security issues).

Render components from string, [ssr] Add Vue function to render VNode to html string #9205 predictable range of element/attributes, so very few edge cases to watch out for). How to render an HTML String with custom Vue Components But it turns out, that v-html can only render plain html. but your browser will not understand it and handle it like a plain old div

Render Raw HTML In Your Vue Apps ← Alligator.io, You wan't to use a Headless CMS, but youdon't want to loose my custom Vue. Render Custom Components from a HTML-String rendered as FancyButton , but your browser will not understand it and handle it like a plain old div element. When Vue is updating a list of elements rendered with v-for, by default it uses an “in-place patch” strategy. If the order of the data items has changed, instead of moving the DOM elements to match the order of the items, Vue will patch each element in-place and make sure it reflects what should be rendered at that particular index.

[ssr] Add Vue function to render VNode to html string · Issue #9205 , Render Functions and JSX You've already seen how to use the template This also enables you to write JSX in your Vue application, which if you're from a React background, you may It'll be automatically added to the element you specify as the Vue element. It can be either a string, or a function that returns a string. Note that you cannot use v-html to compose template partials, because Vue is not a string-based templating engine. Instead, components are preferred as the fundamental unit for UI reuse and composition. Dynamically rendering arbitrary HTML on your website can be very dangerous because it can easily lead to XSS vulnerabilities.

How to render an HTML String with custom Vue Components, Vue render functions give you a better understanding of how Vue works as a whole. Check out how you can fully leverage this (really neat) tool by Vue. This means that fewer elements change, thereby improving performance. you can use the compiler to compile a template string into a render function: But sometimes, we may want to bind the value to a dynamic property on the Vue instance. We can use v-bind to achieve that. In addition, using v-bind allows us to bind the input value to non-string values. Checkbox < input type = "checkbox" v-model = "toggle" true-value = "yes" false-value = "no" > // when checked: vm.toggle === 'yes' // when unchecked: vm.toggle === 'no'

Comments
  • I can make a library recommendation: github.com/alexjoverm/v-runtime-template is a nice abstraction.
  • You don't want to do this for two main reasons: First, Vue.compile adds to your build size, as it's not included by default since it's considered a build-time function. Second, compiling at runtime is "absolutely wrong for production" according to the VueJS docs. The reasoning is compiling a vue component at runtime is the slowest possible way you can render a component in Vue.
  • @NickSteele So how would i do such a thing if i can only return a string and not html directly? I came across this as i am trying to do something similar.
  • @NicoBleiler Do you mean "I can only return a string" as in from a function? I'm not sure I follow your question, but my answer here as to the ways that Vue lets you render components covers pretty much every way you can build dynamic vue components: stackoverflow.com/a/53752539/3196360