Contentful Markdown To Html

Posted on  by admin

Name the new function 'contentful-md-to-html' Make sure the 'Node.js' runtime is selected Choose the option to upload a zip file, then upload the file created in step 1.2. Leave the 'Handler' input set to its default value of index.handler. Migrating from markdown to rich text. If you already have markdown fields, you can use the rich text from markdown package. It automatically converts many specific markdown nodes to rich text, with the option of adding a callback for unsupported nodes. See the documentation for the package for more examples and the list of supported markdown nodes.

  1. Contentful Markdown To Html Format
  2. Contentful Markdown To Html Converter
  3. Contentful Markdown To Html Code
  4. Contentful Markdown To Html Online

Monorepo with Typescript libraries for handling and rendering Contentful Rich Text documents. Packages Official. Converts markdown documents to rich text; rich-text-html-renderer. Converts rich text documents to HTML; rich-text-links. Entity (entry and asset) link extraction utilities; rich-text-plain-text-renderer. I ️ markdown.I like its simplicity and minimalistic API which is good enough to cover most of needed HTML markup. At least for textual content. At work we have a small node based microservice that delivers data from Contentful in exactly markdown format. It's all working well but we started having cases where part of the text is in Contentful and the other part is in that microservice.

A while ago Contentful released a new feature called Rich Text which is a new field type that allows you to create rich text content. It gives you the possibility to format your textual content in all the ways you're used to, making text bold, adding headers, inserting lists, quotes and code etc. This isn't all that exciting as it's been available through the markdown field type for a long time, however, rich text fields are quite different from traditional markdown or html editors. A rich text field stores the content as a typed json structure. Turning your paragraph into something like this:

This typed structure (well, as typed as vanilla javascript can be anyway) allows for greater flexibility and programmability than, for example, markdown. It does come with a cost in excessive bloat, though. Compare the following two paragraps in markdown, html and rich text.

Markdown

HTML

Rich text

That's a lot of json for two small paragraphs, but like I eluded to above, it does come with significant benefits as well. Flexibility, you can create new custom node types with minimal changes to the structure. Programmability, since the structure is very rigid, it's much easier to build a program reading this structure and producing some output than writing a markdown or html parser.

I've played around quite a lot with the rich text structure while I was building support for it into the .NET SDK and I will admit to being quite skeptical at first. I felt like everything rich text could do markdown could do better, but during implementation I came around and changed my mind. A json structure like rich text made writing a parser for the json a breeze, I just created a few classes and a custom deserializer and I suddenly had the entire content structure in strongly typed c#.

As adoption of the rich text field now has grown significantly, even though the feature itself is still in beta, the number of questions around it in the Contentful Community slack has grown as well. One thing that pops up from time to time is how to get your existing content, markdown or html, into a rich text field. For markdown there's already an NPM package provided by Contentful, but I haven't been able to find anything for HTML. I figured it'd be a fun thing to build with F#, as I've never really built anything publicly with it before.

I started out by figuring out the different types I needed and came up with the following.

I then started out by parsing the html using the HtmlParser in the Fsharp.Data package.

This function takes in a list of HtmlNodes and matches on the name of the node, if it's a <p>-tag we turn that into a rich text paragraph. If it doesn't have a name we turn that into a text node. I then filled out the other supported types and a little method for parsing marks, which is attributes that decorate text in rich text lingo, for example, bold, italic, underline etc.

One glaring omission here is <img>-tags, which I haven't handled yet as I haven't fully decided on the strategy. Should the package help you create an asset or should it let you define your own callback for other custom tags you want to handle? I'll ponder this for the next version.

I then created the public functions that takes in the actual html string.

Note how I wrap the entire html in a rich text document-node in the htmlToJson function as this is a required root element in a Contentful rich text structure.

Online

This package is now available as Contentful.RichTextParser on NuGet. I had plans to use the package in an Azure function to make it available for other languages as well, but currently the support for custom nuget packages in Azure Functions is abysmal, so that will have to wait. Anway, below is an example on how the package can be used in conjunction with the .NET SDK to parse HTML and pass it back in a rich text field to Contentful.

I hope you find it useful.

Generating HTML from Markdown at runtime is a great way to load content, but the generated HTML sits outside of the the Angular ecosystem. Here I detail a method for replacing the generated HTML elements in the DOM with dynamically created Angular components

Aim

In this tutorial we will add regular <a> elements to the Markdown with a custom data attribute, and render these as HTML at runtime. We will then query the DOM for the generated HTML, and replace any native <a> elements that contain our custom data attribute with Angular components, the templates of which will contain <a> elements with routerLink directives

Angular Component Template

Why?

Adding a routerLink attribute in the Markdown would have no effect as the generated HTML is just formatted text which is outside the Angular framework. The routerLink attributes would have no functionality. Clicking on such a link would refresh the page and reload the application. We need to generate the anchor elements as Angular components with templates, so the routerLink directives are instantiated and navigation is handled by the Router

Markdown Content

Lets first create some Markdown content, and add the links with a custom data attribute so we can identify the elements in the generated HTML. We will be using marked.js to do the Markdown to HTML conversion

markdown.md

The markdown contains some text, some HTML syntax links with custom data attributes, and a link written in markdown syntax. We have added our routerLink text to this data-routerlink attribute, and will process it at a later stage after the markdown has been rendered as HTML

Most markdown converters allow for raw HTML blocks to be used along with specific markdown syntax like [I'm an inline-style link](https://www.google.com)

marked.js

Contentful markdown to html online

To install marked.js run the following commands

Create a markdown pipe to use as either a service or a template pipe - the complete code can be seen in the StackBlitz demo section ⚡️

Trusted HTML

The HTML generated by marked.js will be bound to an element's innerHTML property in the page's template:

We need to use a pipe to let Angular know that the HTML being bound to the innerHTML property is trusted:

The generated HTML applied to the <div> creates the following elements:

At this point, although the links will work, they would refersh the page and the application would reload. This is why we need to replace the native <a> elements with Angular components

Angular Component

Create the Angular Component

Firstly we need to create a component that will replace the native <a> elements in the DOM

anchor.component.ts

Contentful Markdown To Html Format

Entry Components

As the AnchorComponent will not be used directly in a template i.e. declared to be a required component ahead of time, Angular will ignore it during the build/AOT compilation and tree-shaking phase, and no associated ComponentFactory will be available to generate the component dynamically. For dynamic components wee add the AnchorComponent to the entryComponents array of the containing NgModule

Dynamic Components

For this example, we will be query the DOM for links containing our custom data attribute [data-routerlink]. The attribute values will be used as inputs for the AnchorComponent. We will use a service to dynamically create the Angular components

Component Factory Service

I've created a service with a utility function to generate components based on the Angular component type

Retrieve, Create, Replace

Contentful Markdown To Html Converter

In the host component of the markdown/HTML we will call a function to retrieve the HTML elements that match our custom data attribute, generate AnchorComponent instances, and replace the current HTML elements with our dynamically generated components native elements. The inputs of the generated components will be initialized, and detectChanges() will be called to check and update the component templates

Note that before the addDynamicAnchors() function is called, there is a check to see that the application is running in the browser. If the page is being rendered server side, then the HTML would suffice until pre-rendered HTML is replaced with the template at runtime

To build the components, we need a reference to the ViewContainerRef instance of the targeted HTML element, which is retrieved using the @ViewChild() decorator. The process is detailed in the functions below...

home-page.component.ts

By default, the created components are added as immediate siblings of the ViewContainerRef. I commented out the replace lines of code so we can see what the default behaviour would look like. Here the ViewContainerRef is div.render-div. The two <bc-anchor> components we added are immediatlely below the closing </div> tag. You can also see the <adata-routerlink='..'> elements we want to replace

Contentful Markdown To Html Code

In the forEach loop, the existing anchor elements are replaced with the Angular components hostView elements. If you inspect the image below, you can see that the <bc-anchor> elements are no longer siblings of the div.render-div, but have now been inserted where the <adata-routerlink='..'> elements were previously

Destroy

As a consequence of being added to the application via the ViewContainerRefcreateComponent() function, the generated component's ngOnDestroy() lifecycle hook will be invoked when the containing view is being destroyed. There is one caveat with this: if the created components are part of a page/route that is being reused, they will remain in memory and possibly remain visible in the DOM (depending on where the elements were placed). Further dynamic components will be appended to the ViewContainerRef along with the existing ones. To get around this, we clear the ViewContainerRef each time the page is reused

StackBlitz Demo

Home Link

Contentful Markdown To Html Online

It would be remiss of me not to inlcude one of those dynamically generated links I've been talking about! So here you go, a link to the main blog page - without refreshing the browser 😉