5

I'm playing with Contentful! and I'm having trouble with Rich text content field.

I'm using '@contentful/rich-text-types' and @contentful/rich-text-html-renderer modules to customize the way this block is rendered and to display some assets and reference linked in Rich text content.

After calling getEntries in nuxt asyncData function, I've a description data available in my page component. I'm using documentToHtmlString function with options.

Everything is working fine, but I would like to use a component I have already written (Post.vue), instead of returning the template in ES6 Template Strings.

I know that is possible, but I'm quite new to JS world.

I've tried to require components/post/Post.vue, but I don't know how to use it.

import { BLOCKS } from '@contentful/rich-text-types';
import { documentToHtmlString } from "@contentful/rich-text-html-renderer"

Vue component template where rich text field is rendered

  <section class="container">
    <div class="columns">
      <div class="column">
       <div v-html="formatContent(description)" /> 
      </div>
    </div>
  </section>

I simply call formatContent method to call documentToHtmlString as follow (it works):

  methods: {
    formatContent(content) {
      return documentToHtmlString(content, options)
    }
  }

And customize documentToHtmlString with options as described in doc:

  const embeddedEntryRender = (node) => {
    const { data: { target: entry} } = node

    const fields = entry.fields
    const sys = entry.sys
    // LOOK HERE
    // const postComponent = require('~/components/post/Post')

    return `
      <div class="column is-4">
        <div class="card">

          <div class="card-content">
            <div class="media">
              <div class="media-content">
                <h3 class="title is-4">${fields.title}</h3>
                <div class="subtitle is-6">${fields.description}</div>
              </div>
            </div>

            <div class="content">
            </div>

          </div>
        </div>
      </div> `
  }

  const options = {
    renderNode: {
      [BLOCKS.EMBEDDED_ENTRY]: (node) => embeddedEntryRender(node),
      // [BLOCKS.EMBEDDED_ASSET]: (node) => `<custom-component>${customComponentRenderer(node)}</custom-component>`
    }
  }

No errors detected

--

Thanks a lot

Wonderman
  • 931
  • 10
  • 21

1 Answers1

3

yep you can have a custom vue component in there with a different npm library, I had this same problem.

npm i contentful-rich-text-vue-renderer

in template:

 <rich-text-renderer :document="document" :nodeRenderers="renderNode" />

where 'document' is the data sent form contentful, looks like your calling it description. RenderNode is a method described below.

in script:

    data () {
      return {
        renderNode: [INLINES.ASSET_HYPERLINK]: (node, key, h) => {
            return h('my-vue-component', { key: hey, props: { myProp: 'blah blah' }},'what I want inside the <my-vue-component> tag'`)
      } 
    }

this might be kind of confusing. So First imprt the richTextRenderer component from that npm library and make sure to declare it in the components section of your vue component. (or gloablly)

Next pass into its 'document' prop the contentful rich text field

if you want custom rendering, pass into the nodeRenders prop a function (I had to declare it in the data section)

My example takes any asset hyperlink type and replaces it with a component of what I want inside the tag

I only got this to work if I globally declared the my-vue-component in the main.js file.

import MyVueComponent from 'wherever/it/is';
Vue.component('my-vue-component', MyVueComponent);

there are more configurations for this, just read the npm libs documentation (though its not great docs, it took my a long time to figure out how to pass props down, I had to read their github code to figure that out lol)

Nate
  • 31
  • 2