Как вставить динамический компонент внутри элемента в Angular

Представьте, что у нас есть следующая структура HTML:

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

Теперь содержимое API будет строкой, состоящей из большего количества элементов HTML. Делаем структуру примерно так:

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

Я хочу создать компонент динамически и вставить его в середину дочерних узлов. В данном случае на 5 месте.

Для этого я делаю что-то вроде этого:

HTML-файл:

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

тс файл:

@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);
}

но при этом компонент добавляется как родственный элементу содержимого. Что-то вроде этого:

<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>

Вещи, отображаемые внутри внутреннего HTML, не будут иметь функциональность Angular! вы можете просто разделить внутренний HTML на два содержимого и отобразить их над и под динамическим компонентом!

Naren Murali 05.04.2024 11:48
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
1
198
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Насколько я понимаю из вопроса, вот решение, которое можно найти в файле .ts.

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;

надеюсь, это поможет :)

не уверен, что это сработает для селекторов компонентов Angular, поскольку его нужно создавать динамически, и простое использование document.createElement, я думаю, не сработает.

coding life 08.04.2024 14:54
Ответ принят как подходящий

Внутри innerHTML можно вставить компонент Angular, но следует отметить, что элементы, вставленные таким образом, находятся вне контекста Angular, и обнаружение изменений не будет работать, поэтому он будет вести себя как обычный элемент HTML. Лучше искать альтернативные подходы и не использовать innerHTML. Ниже приведен пример, подчеркивающий мою точку зрения о том, что обнаружение изменений не работает внутри InternalHTML.

полный код

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.info(insertElement);
    this.renderer2.appendChild(
      insertElement.children[4],
      componentRef.location.nativeElement
    );
    this.articleContent.createComponent(DynamicComponent, {
      index: 0,
    });
    componentRef.hostView.detectChanges();
  }
}

bootstrapApplication(App);

Демо-версия Stackblitz

спасибо за решение @NarenMurali, для моего варианта использования это решение идеально подходит, поскольку динамический компонент, который я визуализирую, имеет статический контент с некоторыми генераторами событий, которые работают отлично.

coding life 08.04.2024 22:04

Другие вопросы по теме