Tengo esto
https://angular-dynamic-component-append.stackblitz.io/
Logré agregar dinámicamente un elemento, pero no se compiló. Vi muchos tutoriales como esto
Pero no es realmente lo que necesito. Y a menudo usan la notación hashtag para identificar el contenedor.
Necesito agregar un componente a cualquier elemento que pueda tener mi directiva personalizada.
También necesitaría usar el valor de enlace de la directiva para controlar un atributo [oculto] en el elemento adjunto.
LOS OBJETIVOS
- Anular el comportamiento del componente existente:
- agregar un atributo para mostrar / ocultar
- agregando una clase para personalizar la apariencia
- Reduce la codificación html
- No es necesario escribir todo el componente
<my-comp></mycomp>
- No es necesario conocer la clase
- Comportamiento automático si se cambia el nombre de la clase
- Cambiar el elemento sobre el que se aplica la directiva
- El objetivo final será agregar una clase al elemento contenedor
- No es necesario escribir todo el componente
Fuente esperada
<div [myDirective]="myBoolean">
<p>some content</p>
</div>
Esperada compilada
<div [myDirective]="myBoolean" class="myDirectiveClass1">
<p>some content</p>
<someComponent [hidden]="myBoolean" class="myDirectiveClass2"></someComponent>
</div>
¿Hay alguna manera de lograrlo?
Gracias de antemano
3 respuestas
Así es como lo hice funcionar
import {
Renderer2,
Directive,
Input,
ElementRef,
OnChanges,
ViewEncapsulation
} from "@angular/core";
import { MatSpinner } from "@angular/material";
@Directive({
selector: "[myDirective]"
})
export class MyDirective {
@Input()
set myDirective(newValue: boolean) {
console.info("myDirectiveBind", newValue);
if (!!this._$matCard) {
const method = newValue ? "removeClass" : "addClass";
this.renderer[method](this._$matCard, "ng-hide");
}
this._myDirective = newValue;
}
private _myDirective: boolean;
private _$matCard;
constructor(private targetEl: ElementRef, private renderer: Renderer2) {
this._$matCard = this.renderer.createElement('mat-card');
const matCardInner = this.renderer.createText('Dynamic card!');
this.renderer.addClass(this._$matCard, "mat-card");
this.renderer.appendChild(this._$matCard, matCardInner);
const container = this.targetEl.nativeElement;
this.renderer.appendChild(container, this._$matCard);
}
}
import {
Component,
ElementRef,
AfterViewInit,
ViewEncapsulation
} from '@angular/core';
@Component({
selector: 'card-overview-example',
templateUrl: 'card-overview-example.html',
styleUrls: ['card-overview-example.css']
})
export class CardOverviewExample {
hideMyDirective = !1;
constructor(private _elementRef: ElementRef) { }
getElementRef() {
return this._elementRef;
}
ngAfterViewInit() {
let element = this._elementRef.nativeElement;
let parent = element.parentNode;
element.parentNode.className += " pippo";
}
}
.ng-hide {
display: none;
}
<mat-card>Simple card</mat-card>
<div class="text-center">
<button (click)="hideMyDirective = !hideMyDirective">
Toggle show dynamic card
</button>
</div>
<br />
<span>hideMyDirective: {{hideMyDirective}}</span>
<hr />
<div class="myDiv" [myDirective]="hideMyDirective">
<ul>
<li>My content</li>
</ul>
</div>
Es muy simple Acabo de hacerte un ejemplo.
Por favor, lea los comentarios dentro de la directiva del cargador.
https://github.com/garapa/studying/tree/master/loader
Editar:
Tu componente:
export class LoaderComponent {
loading;
constructor() { }
}
Su directiva
export class LoaderDirective implements OnDestroy {
private componentInstance: ComponentRef<LoaderComponent> = null;
@Input()
set appLoader(loading: boolean) {
this.toggleLoader(loading);
}
constructor(
private viewContainerRef: ViewContainerRef,
private componentFactoryResolver: ComponentFactoryResolver
) { }
toggleLoader(loading: boolean) {
if (!this.componentInstance) {
this.createLoaderComponent();
this.makeComponentAChild();
}
this.componentInstance.instance.loading = loading;
}
private createLoaderComponent() {
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(LoaderComponent);
this.componentInstance = this.viewContainerRef.createComponent(componentFactory);
}
private makeComponentAChild(){
const loaderComponentElement = this.componentInstance.location.nativeElement;
const sibling: HTMLElement = loaderComponentElement.previousSibling;
sibling.insertBefore(loaderComponentElement, sibling.firstChild);
}
ngOnDestroy(): void {
if (this.componentInstance) {
this.componentInstance.destroy();
}
}
}
Tu modulo
@NgModule({
...
entryComponents: [
LoaderComponent
]
})
Dentro del archivo html del componente en el que se inserta el componente:
<div #target>
</div>
Dentro del archivo ts del componente en el que se inserta el componente:
'Component_to_insert' -> es el componente que se insertará dentro de otro componente.
import { Component_to_insert } from 'path';
import { Component, ViewChild, ViewContainerRef, ComponentFactoryResolver, AfterViewInit } from '@angular/core';
@Component({
selector: 'component-name',
templateUrl: 'component.html',
styleUrls: ['component.scss'],
entryComponents: [Component_to_insert]
})
export class ManagetemplatesPanelComponent implements AfterViewInit {
@ViewChild('target', { read: ViewContainerRef }) entry: ViewContainerRef;
constructor(private resolver: ComponentFactoryResolver) { }
ngAfterViewInit() {
this.createComponent();
}
createComponent() {
this.entry.clear();
const factory = this.resolver.resolveComponentFactory(Component_to_insert);
const componentRef = this.entry.createComponent(factory);
}
}
Nuevas preguntas
angular
Preguntas sobre Angular (que no debe confundirse con AngularJS), el marco web de Google. Use esta etiqueta para preguntas angulares que no son específicas de una versión individual. Para el marco web anterior de AngularJS (1.x), use la etiqueta angularjs.