Al trabajar con Astro.js y la API Headless Delivery de Umbraco, uno de los retos a los que pueden enfrentarse los desarrolladores es la representación dinámica de contenido de texto enriquecido almacenado como JSON. A diferencia del contenido HTML tradicional que se puede inyectar mediante set:html
, los datos JSON estructurados requieren un enfoque más flexible, especialmente cuando se necesita integrar componentes personalizados para manejar elementos específicos.
La directiva set:
html de Astro es una forma habitual de renderizar contenido HTML sin procesar de forma segura. Sin embargo, cuando se trata de JSON estructurado, como el elemento umb-rte
de Umbraco, este método se vuelve limitante. Necesitamos una forma de analizar la estructura JSON y renderizar dinámicamente los componentes apropiados manteniendo la arquitectura basada en componentes de Astro.
Para manejar esto, podemos crear un componente Astro recursivo que procese el JSON y renderice los elementos apropiados usando componentes Astro. Los tipos en el siguiente código fueron generados usando el paquete Umbraco.Community.DeliveryApiExtensions, que ayuda a definir tipos fuertes para la respuesta JSON. Usando tipos fuertes y extensiones de la comunidad como Umbraco.Community.DeliveryApiExtensions, aseguramos un manejo más seguro y predecible del contenido basado en JSON.
Ejemplo Json:
"blogRichText": {
"tag": "#root",
"attributes": {},
"elements": [
{
"tag": "p",
"attributes": {
"id": "someId",
"class": "some-class"
},
"elements": [
{
"text": "This is ",
"tag": "#text"
},
{
"tag": "strong",
"attributes": {},
"elements": [
{
"text": "bold text",
"tag": "#text"
}
]
},
{
"text": " with an object following",
"tag": "#text"
}
]
},
{
"tag": "umb-rte-block",
"attributes": {
"content-id": "705a6633-3e20-4f3a-be76-4b450a397608"
},
"elements": []
},
{
"tag": "p",
"attributes": {},
"elements": [
{
"text": "with some more text",
"tag": "#text"
}
]
}
],
"blocks": [
{
"content": {
"contentType": "angularCounter",
"id": "705a6633-3e20-4f3a-be76-4b450a397608",
"properties": {}
},
"settings": null
}
]
}
RichTextField.astro
---
import type { RichTextGenericElementModel , RichTextRootElementModel , RichTextTextElementModel } from"@/api/umbraco";
import {richTextFieldHasContent} from"./RichTextHelper"import RenderRichText from'./RenderRichText.astro';
interface Props {
richTextField: RichTextGenericElementModel | RichTextRootElementModel | RichTextTextElementModel | null | undefined;
}
const { richTextField } = Astro.props;
if (!richTextFieldHasContent(richTextField)) returnnull;
// If the field is the root element, grab the blocks for use in block elements.let blocks: any[] = [];
if (richTextField && richTextField.tag === '#root') {
const root = richTextField as RichTextRootElementModel;
blocks = root.blocks;
}
---
<divclass="rich-text-block container mx-auto px-[15px]"><RenderRichTextnode={richTextField}blocks={blocks}></div>
RenderRichText.astro:
---
// filepath: /src/components/richText/RenderRichText.astro
import RichTextFieldBlockItem from './RichTextFieldBlockItem.astro';
import type { ApiBlockItemModel, RichTextGenericElementModel, RichTextRootElementModel, RichTextTextElementModel } from "@/api/umbraco";
import RenderRichTextComponent from './RenderRichText.astro';
interface Props {
node: RichTextGenericElementModel | RichTextRootElementModel | RichTextTextElementModel | null | undefined;
blocks: ApiBlockItemModel[] | null | undefined;
}
const { node, blocks } = Astro.props;
if (!node) return null;
const voidElements = [
"area",
"base",
"br",
"col",
"embed",
"hr",
"img",
"input",
"link",
"meta",
"param",
"source",
"track",
"wbr"
];
const isText = node.tag === '#text';
const textNode = isText ? nodeas RichTextTextElementModel : null;
const isRoot = node.tag === '#root';
const rootNode = isRoot ? nodeas RichTextRootElementModel : null;
const isBlock = node.tag === 'umb-rte-block';
const blockNode = isBlock ? nodeas RichTextGenericElementModel : null;
const block = isBlock ? blocks?.find((b) => b.content && b.content.id === blockNode?.attributes['content-id']) : null;
const isGeneric = !isText && !isRoot && !isBlock;
const genericNode = isGeneric ? nodeas RichTextGenericElementModel : null;
const GenericTag = genericNode?.tag|| 'div';
const isVoidElement = voidElements.includes(GenericTag);
---
{isText && <Fragment set:html={textNode?.text}></Fragment>}
{isRoot && rootNode?.elements.map((child, i) =>
<RenderRichTextComponent node={child} blocks={blocks} />)}
{isBlock && <RichTextFieldBlockItem block={block} />}
{isGeneric && isVoidElement && (
<GenericTag {...genericNode?.attributes} />
)}
{isGeneric && !isVoidElement && (
<GenericTag {...genericNode?.attributes}>
{genericNode?.elements.map((child, i) =>
)}
</GenericTag>
)}
umb-rte-element
, pasa los datos del bloque asociado a un RichTextFieldBlockItem que determina el componente astro que debe renderizar el bloque.Este enfoque proporciona a los desarrolladores de Astro.js que trabajan con la API Headless Delivery de Umbraco una forma estructurada de renderizar texto enriquecido sin depender de set:html
y permite consumir fácilmente componentes astro normales para la renderización .
Si estás integrando la API Headless Delivery de Umbraco con Astro.js, el manejo adecuado de texto enriquecido JSON es clave para una experiencia fluida del desarrollador. Con este método, puedes mantener una estructura limpia basada en componentes mientras renderizas contenido dinámico eficientemente.
7 de febrero de 2025
28 de mayo de 2024
El equipo de Given Data LLC monitorea continuamente los avances en el espacio de gestión de contenido, lo que nos mantiene por delante de la competencia. ¿Necesidad urgente? llamanos