javascript - Adăugarea programatică a componentelor în poziții dinamice în Angular
Punctul meu de plecare este un fel de fragment HTML, care este încărcat la runtime de pe backend-ul meu, cu etichete de substituenți:
<table>
<tbody>
<tr>
<td>
<span>Col1</span>
</td>
<td>
<span class="placeholderClass" data-placeholderdata="xy"></span>
</td>
</tr>
</tbody>
</table>
Vreau să afișez fragmentul HTML, dar să înlocuiesc toate elementele <span class="placeholderClass"/> cu propriul meu component Angular.
Până acum am citit despre încărcătorul de componente dinamice din Angular, dar din câte am înțeles, acesta îmi permite doar să încarc o componentă dinamică într-o poziție fixă, și nu o componentă fixă într-o poziție dinamică.
De asemenea, am încercat următoarea postare: Angular 2 Inserarea dinamică a unui component într-un nod DOM specific fără a folosi ViewContainerRef
Componenta Secțiune este componenta mea principală unde stochez HTML-ul și Componenta Valoare componenta pe care vreau să o înlocuiesc.
Componentă Secțiune:
HTML
<div [innerHTML]=sectionSnippet></div>
TS
@Component({
selector: 'section-view',
templateUrl: './section.component.html',
styleUrls: ['./section.component.sass'],
encapsulation: ViewEncapsulation.ShadowDom
})
export class SectionComponent implements OnInit {
@Input() sectionSnippetInput = '';
constructor(private sanitizer: DomSanitizer,
private resolver: ComponentFactoryResolver,
private injector: Injector,
private app: ApplicationRef) {
}
ngOnInit(): void {
this.replaceTags();
}
private replaceTags() {
let temp:HTMLDivElement = document.createElement('div');
temp.innerHTML = this.sectionSnippetInput;
let placeholders: HTMLCollectionOf<Element> = temp.getElementsByClassName('placeholderClass')
for (let i = 0; i < placeholders.length; i++) {
//dynamically create angular comp
let factory = this.resolver.resolveComponentFactory(ValueComponent);
//create instance with the value placeholder as parent
const ref = factory.create(this.injector, [], placeholders[i]);
//manually init comp
ref.instance.initElem = placeholders[i];
ref.instance.initComp();
//trigger re-rendering
ref.changeDetectorRef.detectChanges();
//attach newly created component to our angular context
this.app.attachView(ref.hostView);
}
this.sectionSnippetInput = temp.innerHTML;
}
get sectionSnippet() {
return this.sanitizer.bypassSecurityTrustHtml(this.sectionSnippetInput);
}
}
Componentă de valoare:
HTML
<span (click)="testCallback()">{{getFormatNumber()}}</span>
TS
@Component({
selector: 'value',
templateUrl: './value.component.html',
styleUrls: ['./value.component.sass']
})
export class ValueComponent implements AfterViewInit {
public param1:string|null = '';
public initElem: Element | null | undefined;
public testCallback(){
alert("Test")
}
ngAfterViewInit(): void{
this.initComp();
}
public initComp() {
// @ts-ignore
this.param1 = this.initElem.getAttribute("data-placeholderdata");
}
getFormatNumber(){
//some formatting code
return this.param1;
}
}
Care pare să funcționeze, cel puțin pentru redarea inițială, dar legăturile Angular precum (click) nu funcționează. Bănuiesc că componenta creată recent nu este legată corect de contextul Angular, prin urmare nu înregistrează evenimentele de click.
(Folosind Angular V13)
Deoarece sunt nou în Angular, poate cineva să-mi dea un sfat despre cum să procedez. Este o idee bună să folosesc ComponentFactory sau ar trebui să încerc altceva?