skip to Main Content

Imagine we have a html structure as follows

<div [innerHTML]="contentFromAPI | safeHTML"></div>

Now the content from the api would be a string consists of more HTML elements. Making the structure something like this:

<div>
 <p></p>
 <p></p>
 <p></p>
 <p></p>
 <p></p>
 <p></p>
 <p></p>
 <p></p>
 <p></p>
 <p></p>
</div>

I want to create a component dynamically and insert it at the middle of the child nodes. In this case at the 5th place.

For this I’m doing something like this:

html file:

<div [innerHTML]="contentFromAPI | safeHTML" #articleContent></div>

ts file:

@ViewChild('articleContent', { read: ViewContainerRef })
  private articleContent!: ViewContainerRef;

ngOnChanges(){
 if(ads){
   this.addElementToTemplate();
 }
}

private addElementToTemplate() {
setTimeout(() => {
      const childrenLength =
        this.articleContent.element.nativeElement.children.length;
        this.articleContent.createComponent(DynamicElement,{index: Math.ceil(childrenLength/2)});
    }, 3000);
}

but this adds the component as a sibling to content element. Something like this:

<div>
     <p></p>
     <p></p>
     <p></p>
     <p></p>
     <p></p>
     <p></p>
     <p></p>
     <p></p>
     <p></p>
     <p></p>
</div>
<dynamic-element></dynamic-element>

2

Answers


  1. From What i understand form the question, here is solution which can be worked out in the .ts file.

    this.contentFromAPI = //your data from API here;
    
    const parser = new DOMParser();
    const doc = parser.parseFromString(this.contentFromAPI, 'text/html');
    
    // Get the element at the 5th position
    //add logic to find middle node here instead of 4
    const targetElement = doc.body.childNodes[4];
    
    const componentElement = document.createElement('your-dynamic-component');
    
    
    targetElement.parentNode.insertBefore(componentElement, targetElement);
    
    // Update the contentFromAPI with the modified HTML structure
    this.contentFromAPI = doc.body.innerHTML;
    

    hope this would helps 🙂

    Login or Signup to reply.
  2. It is possible to insert an angular component inside innerHTML but we should note that elements inserted this way are outside angular context and change detection will not work, so it will behave like a normal HTML element. Its better you looks for alternative approaches and not using innerHTML, Please find below example highlighting my point that change detection does not work inside innerHTML

    full code

    import {
      ApplicationRef,
      Component,
      Renderer2,
      ViewChild,
      ViewContainerRef,
      createComponent,
    } from '@angular/core';
    import { bootstrapApplication } from '@angular/platform-browser';
    import 'zone.js';
    import { SafeHtmlPipe } from './safe-html.pipe';
    import { CommonModule } from '@angular/common';
    import { DynamicComponent } from './app/dynamic/dynamic.component';
    
    @Component({
      selector: 'app-root',
      standalone: true,
      imports: [SafeHtmlPipe, CommonModule, DynamicComponent],
      template: `
        <div [innerHTML]="contentFromAPI | safeHtml" #articleContent></div>
      `,
    })
    export class App {
      @ViewChild('articleContent', { read: ViewContainerRef })
      private articleContent!: ViewContainerRef;
      name = 'Angular';
      contentFromAPI = `
      <p>1</p>
      <p>2</p>
      <p>3</p>
      <p>4</p>
      <p>5. insert here!</p>
      <p>6</p>
      <p>7</p>
      <p>8</p>
      <p>9</p>
      <p>10</p>
      `;
    
      constructor(
        private renderer2: Renderer2,
        private applicationRef: ApplicationRef
      ) {}
    
      ngAfterViewInit() {
        this.addElementToTemplate();
      }
    
      private addElementToTemplate() {
        const environmentInjector = this.applicationRef.injector;
        const componentRef = createComponent(DynamicComponent, {
          environmentInjector,
        });
        const insertElement = this.articleContent.element.nativeElement;
        console.log(insertElement);
        this.renderer2.appendChild(
          insertElement.children[4],
          componentRef.location.nativeElement
        );
        this.articleContent.createComponent(DynamicComponent, {
          index: 0,
        });
        componentRef.hostView.detectChanges();
      }
    }
    
    bootstrapApplication(App);
    

    Stackblitz Demo

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search