2

I have a rich text element in Contentful that has an embedded entry within it. I am attempting to have that embedded entry render inside a custom Angular component. However, when I pass in options to the Contentful documentToHtmlString function, it displays the tag, but does not render anything or even trigger the console.log() function I have inside the custom component typescript file.

TYPESCRIPT for the rendering

convertToHTML(document:any[]) {
    const options = {
      renderNode: {
        [BLOCKS.EMBEDDED_ENTRY]: (node:any, next:any) => `<embed-element [node]="${node}" [content]="${next(node.content)}"></embed-element>`
      }
    }
    let unsafe = documentToHtmlString(document, options);
    return this.sanitizer.bypassSecurityTrustHtml(unsafe);
}

HTML for the rendering

<span [innerHTML]="convertToHTML(article.fields.content)"></span>

I have loaded the custom element <embed-element></embed-element> in the providers section of the app.module.ts file as well.

import { EmbedElementComponent } from './shared/components/embed-element/embed-element.component';

@NgModule({
   declarations: [
     ...
     EmbedElementComponent
   ],
   providers: [
     ...
     EmbedElementComponent
   ]
})

Then inside typescript file for the custom element, I just simply have a console.log in the onInit function for testing purposes. I am not seeing this occur in the console.

import { Component, OnInit, Input } from '@angular/core';

@Component({
  selector: 'embed-element',
  templateUrl: './embed-element.component.html',
  styleUrls: ['./embed-element.component.css']
})
export class EmbedElementComponent implements OnInit {

  @Input() node: any;
  @Input() content: any;

  constructor() { }

  ngOnInit(): void {
    console.log(this.node);
  }

}

And in the HTML for the custom element, I removed the <p> tag just in case it was stripping it out as "unsafe" and replaced it with the following:

EMBEDDED ELEMENT WORKS!!!!!

Finally, I see nothing appear on screen for this custom element once everything is rendered. Inside the inspect element however, this is what I get.

<embed-element [node]="[object Object]" [content]=""></embed-element>

How do I manage to make the custom element actually get called in this aspect? And at least receive the console log message I am requesting inside the custom element?

SDMitch
  • 39
  • 2
  • 6

2 Answers2

1

Not sure if you still needed another solution, but I came across ngx-dynamic-hooks https://github.com/MTobisch/ngx-dynamic-hooks - and was able to reuse my custom components within the inner html.

const cmpt_data = {
 title: 'This is a test'
};
const headerFooterRichTextOption: Partial<Options>  = {
  renderNode: {
    ["embedded-entry-inline"]: (node, next) => `${this.embeddedContentfulEntry(node.nodeType, node.data)}`,
    ["paragraph"]: (node, next) => `<span>${next(node.content)}</span>`,
  }
};
const d = documentToHtmlString(tt.value, headerFooterRichTextOption);
const hSanit = this.sanitizer.bypassSecurityTrustHtml(d);


embeddedContentfulEntry(nodeType: any, data: any) {
  return "<custom-component [title]='context.title'></custom-component>";
}
<ngx-dynamic-hooks [content]="hSanit" [context]="cpmt_data"></ngx-dynamic-hooks>
atang
  • 72
  • 2
  • 8
0

I believe that using a custom component for this type of situation was not working because it was rendering outside of Angulars scope or after initial components initiation.

I resolved this issue by essentially just removing the custom element all together and creating a function that renders the embedded element as I wanted.

// Notice the new function call, renderCustomElement()
convertToHTML(document:any[]) {
    const options = {
      renderNode: {
        [BLOCKS.EMBEDDED_ENTRY]: (node:any, next:any) => this.renderCustomElement(node)
      }
    }
    let unsafe = documentToHtmlString(document, options);
    return this.sanitizer.bypassSecurityTrustHtml(unsafe);
  }

And finally that function that simply creates some basic html with Bootstrap styling and returns that back to be rendered.

renderCustomElement(node:any) {
    let link = `/support-center/article/${node.data.target.fields.category[0].sys.id}/${node.data.target.sys.id}`;
    return `<style>.card:hover{box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 15%) !important;}</style><a class="card clickable mb-2 text-decoration-none text-dark" href="${link}" target="_blank"><div class="card-header">Article</div><div class="card-body"><h4 class="fw-light">${node.data.target.fields.title}</h4><p class="fw-light pb-0 mb-0">${node.data.target.fields.preview}</p></div></a>`
  }
SDMitch
  • 39
  • 2
  • 6