2

I'm attempting to make a page which will load a text string (https://pastebin.com/Mp9sKy1A) into a page and then replace any instance of --FML-[componentName] with the appropriate component.

So for example --FML-[NoteBlock] would be automatically replaced with the NoteBlock component.

This is what I have so far:

pureContent () {
      const c = this.content.replaced
      const re = new RegExp(`<p>--FML-\\[(\\w+)\\]</p>`, 'g')
      return c.replace(re, ($0, $1) => `<component v-bind:is="${$1.toLowerCase()}"></component>`)
    }

The output will then be placed into the following template:

<template>
  <div>
    <site-header></site-header>
    <div class="wrapper">
      <side-bar></side-bar>
      <main class="container" v-html="pureContent()" />
    </div>
  </div>
</template>

It actually sort of works. However the component part isn't being pulled in as an actual component, rather a <component> HTML tag, which obviously isn't the desired result. Is there a way to make it work as desired?

Here is the full SFC file if anyone is interested: https://pastebin.com/yb4CJ1Ew

This is the output I am currently getting:

<main data-v-86dcc3c4="" class="container">
  <h1 id="creating-new-contexts">Creating new contexts</h1>
  <h2 id="section-title">Section Title</h2>
  <h3 id="section-subtitle-that-contains-additional-information">
    Section subtitle that contains additional information
  </h3>
  <p>
    Cillum ipsum ad veniam elit non. Sunt ea ut quis qui dolore id voluptate
    magna. Ex non commodo reprehenderit ipsum irure. Ad excepteur nulla ullamco
    et deserunt magna et sint reprehenderit sint esse commodo. Tempor duis anim
    nisi commodo incididunt ut ex et sunt laborum excepteur ea culpa laborum.
  </p>
  <component v-bind:is="noteblock"></component>
  <p>
    Officia esse Lorem ad duis dolore nostrud ex elit aliqua incididunt sint ad
    ex. Eiusmod do in ad aute nulla eiusmod tempor Lorem non. Qui sunt voluptate
    laborum mollit elit adipisicing minim dolore voluptate veniam incididunt
    proident ullamco. Ipsum est cupidatat occaecat pariatur ut aute.
  </p>
  <component v-bind:is="codeexample"></component>
  <component v-bind:is="propstable"></component>
</main>

The <component> tags should be actual Vue components

3
  • Does this seem like an approach you could use? Commented Nov 29, 2018 at 15:45
  • Unforunately I don't think that would work as it still requires me putting <component ... in my main template and I just have no idea where those components are going to appear in the body. I don't really have any choice but to work out a way to render them from the text file as it is. Commented Nov 29, 2018 at 16:00
  • You would make one component that includes all the text where replacements are to be made. Commented Nov 29, 2018 at 16:23

1 Answer 1

4

You can't do it with v-html:

Updates the element’s innerHTML. Note that the contents are inserted as plain HTML - they will not be compiled as Vue templates. If you find yourself trying to compose templates using v-html, try to rethink the solution by using components instead.

You're already using dynamic components, you just need One Component To Rule Them All (and in the document bind them).

You could, in fact, use non-dynamic components internally, if you wanted to define your noteblock, et. al. as components rather than data items, but you definitely need the container to be a dynamic component, as that's the only way you can turn text data into Vue-managed DOM.

new Vue({
  el: '#app',
  data: {
    preContent: "<h1 id=\"creating-new-contexts\">Creating new contexts</h1>\n<h2 id=\"section-title\">Section Title</h2>\n<h3 id=\"section-subtitle-that-contains-additional-information\">Section subtitle that contains additional information</h3>\n<p>Cillum ipsum ad veniam elit non. Sunt ea ut quis qui dolore id voluptate magna. Ex non commodo reprehenderit ipsum irure. Ad excepteur nulla ullamco et deserunt magna et sint reprehenderit sint esse commodo. Tempor duis anim nisi commodo incididunt ut ex et sunt laborum excepteur ea culpa laborum.</p>\n<p>--FML-[NoteBlock]</p>\n<p>Officia esse Lorem ad duis dolore nostrud ex elit aliqua incididunt sint ad ex. Eiusmod do in ad aute nulla eiusmod tempor Lorem non. Qui sunt voluptate laborum mollit elit adipisicing minim dolore voluptate veniam incididunt proident ullamco. Ipsum est cupidatat occaecat pariatur ut aute.</p>\n<p>--FML-[CodeExample]</p>\n<p>--FML-[PropsTable]</p>\n"
  },
  computed: {
    pureContent() {
      const c = this.preContent;
      const re = new RegExp(`<p>--FML-\\[(\\w+)\\]</p>`, 'g');

      return c.replace(re, ($0, $1) => `<component v-bind:is="${$1.toLowerCase()}"></component>`);
    },
    postProcessSpec() {
      return {
        template: `<div>${this.pureContent}</div>`,
        data() {
          return {
            codeexample: {
              template: '<pre>This is the CODEEXAMPLE component</pre>'
            },
            noteblock: {
              template: '<div>This is the NOTEBLOCK component</div>'
            },
            propstable: {
              template: '<table border=1><th>PROPS TABLE!</th></table>'
            }
          }
        },
        components: {}
      };
    }
  }
});
<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
  <component :is="postProcessSpec"></component>
</div>

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

6 Comments

I'm tempted to accept this as the answer just for the LOTR reference :) Thanks, Roy, that makes sense. I'll see if I can get it working like this.
That worked! Thanks. I made a slight modification so that I could use the existing .vue components via imports: pastebin.com/FrWHPmLu Do you know how I could pass props to these components?
Depending on what takes what kind of props, you might do v-bind="propsObj" to avoid having to be specific about prop names. Other than that, I don't think there's any trick: pass them to postProcessSpec and include the bindings in the template.
Thank you! I didn't think to pass them to postProcessSpec first! All working now.
Hello, thanks to your Answer in my other post I came here, one Question is if this actually supports SSR and how I can pass custom props to the Component for example <swiper :options="...."></swiper>
|

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.