Reputation: 10040
I have the following rich text document
{
"data":{},
"content":[
{
"data":{},
"content":[
{
"data":{},
"marks":[ ],
"value":"test",
"nodeType":"text"
}, {
"data":{},
"marks":[],
"value":"",
"nodeType":"text"
}
],
"nodeType":"paragraph"
},
{
"data":{
"target":{
"sys":{
"space":{
"sys":{
"type":"Link",
"linkType":"Space",
"id":"gedg1u5b0yz9"
}
},
"id":"2CzKe2pWvewCiek6w0yyoQ",
"type":"Asset",
"createdAt":"2019-01-07T22:37:55.473Z",
"updatedAt":"2019-01-07T22:37:55.473Z",
"environment":{
"sys":{
"id":"master",
"type":"Link",
"linkType":"Environment"
}
},
"revision":1,
"locale":"en-US"
},
"fields":{
"title":"Test Image",
"description":"Image for testing",
"file":{
"url":"//images.ctfassets.net/<hidden>/<hidden>/<hidden>/IMG_2878.JPG",
"details":{
"size":3874595,
"image":{
"width":5184,
"height":3456
}
},
"fileName":"IMG_2878.JPG",
"contentType":"image/jpeg"
}
}
}
},
"content":[],
"nodeType":"embedded-asset-block"
},
{
"data":{},
"content":[
{
"data":{},
"marks":[],
"value":"",
"nodeType":"text"
}
],
"nodeType":"paragraph"
}
],
"nodeType":"document"
}
When I use documentToHtmlString (from here https://www.npmjs.com/package/@contentful/rich-text-html-renderer)
documentToHtmlString(document);
It outputs the following
<p>test</p><p></p>
Anyone know how to get it to output the img tag as well?
Upvotes: 12
Views: 5915
Reputation: 992
Here's a solution that doesn't rely on the fields
property existing.
I'm using Contentful with SvelteKit via GraphQL. I don't know whether it's my setup or whether the Contentful API has changed, but the node data received by my renderNode
options callback (as seen in the other answers) doesn't contain fields
.
Contentful's recommended <custom-component>
approach doesn't work for me in SvelteKit.
I use the renderNode
callback to save the asset link info and return a unique text "marker" that is embedded into the result string. After documentToHtmlString()
completes, I fetch the image associated with each link and then search-and-replace the marker with the final HTML.
Define this function richTextToHTML()
and call html = await richTextToHTML(json)
instead of html = documentToHtmlString(json)
. You may need to replace contentfulFetch()
with your query call and adjust the resulting <img>
width and height.
async function richTextToHTML( json )
{
const asset_links = [];
const options = {
renderNode: {
[BLOCKS.EMBEDDED_ASSET]:
(node) => { return `[embedded-asset-block:${asset_links.push(node.data.target.sys)}]`; }
}
};
let html = documentToHtmlString( json, options );
for (let i=0; i<asset_links.length; ++i) {
const link = asset_links[i]
const asset_query = `
{
asset(id:"${link.id}")
{
title
description
url
width
height
}
}
`
let replacement = '';
const response = await contentfulFetch(asset_query);
if (response.ok) {
const asset = (await response.json()).data.asset;
replacement = `<img src="${asset.url}" alt="${asset.description}" style="max-width:800px; height:auto;">`;
const marker = `[embedded-asset-block:${i+1}]`;
html = html.replace( marker, replacement );
}
}
return html;
}
Upvotes: 0
Reputation: 10040
From https://github.com/contentful/rich-text/issues/58#issuecomment-452236848
You need to specify how to render that You can find more about it here https://github.com/contentful/rich-text/tree/master/packages/rich-text-html-renderer#usage
import { BLOCKS } from '@contentful/rich-text-types';
import { documentToHtmlString } from '@contentful/rich-text-html-renderer';
const options = {
renderNode: {
[BLOCKS.EMBEDDED_ENTRY]: (node) => `<custom-component>${customComponentRenderer(node)}</custom-component>`
}
}
documentToHtmlString(document, options);
My specific resolution was:
const options = {
renderNode: {
[BLOCKS.EMBEDDED_ASSET]: ({ data: { target: { fields }}}) =>
`<img src="${fields.file.url}" height="${fields.file.details.image.height}" width="${fields.file.details.image.width}" alt="${fields.description}"/>`,
},
};
Upvotes: 14
Reputation: 193
const options = {
renderNode: {
[BLOCKS.EMBEDDED_ASSET]: ({ data: { target: { fields }}}) =>
<div dangerouslySetInnerHTML={{__html: `<img src="${fields.file['en-GB'].url}" alt="${fields.title['en-GB']}"/>`}} />,
},
};
I found i needed to set dangerouslySetInnerHTML
for it to render properly in the browser.
Upvotes: 1