Представьте, что у нас есть следующая структура 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>
Насколько я понимаю из вопроса, вот решение, которое можно найти в файле .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
, я думаю, не сработает.
Внутри 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);
спасибо за решение @NarenMurali, для моего варианта использования это решение идеально подходит, поскольку динамический компонент, который я визуализирую, имеет статический контент с некоторыми генераторами событий, которые работают отлично.
Вещи, отображаемые внутри внутреннего HTML, не будут иметь функциональность Angular! вы можете просто разделить внутренний HTML на два содержимого и отобразить их над и под динамическим компонентом!