web-dev-qa-db-fra.com

Ajouter dynamiquement le composant à div en Angular 5

J'ai ceci

https://angular-dynamic-component-append.stackblitz.io/

J'ai réussi à ajouter dynamiquement un élément, mais il n'est pas compilé. J'ai vu de nombreux tutoriels comme this

Mais ce n'est pas vraiment ce dont j'ai besoin. Et souvent, ils utilisent la notation hashtag pour identifier le conteneur.

J'ai besoin d'ajouter un composant à n'importe quel élément pouvant contenir ma directive personnalisée.

J'aurais également besoin d'utiliser la valeur de liaison de la directive pour contrôler un attribut [caché] sur l'élément ajouté.

LES BUTS

  1. Remplacer le comportement du composant existant:
    • ajout d'un attribut pour afficher/masquer
    • ajout d'une classe pour personnaliser l'apparence
  2. Réduisez le codage html
    • Pas besoin d'écrire le composant entier <my-comp></mycomp>
    • Pas besoin de connaître la classe
    • Comportement automatique si le nom de classe est modifié
      1. Modification de l'élément sur lequel la directive est appliquée
    • L'objectif final sera d'ajouter une classe à l'élément contaner

Source attendue

<div [myDirective]="myBoolean">
    <p>some content</p>
</div>

Compilé attendu

<div [myDirective]="myBoolean" class="myDirectiveClass1">
    <p>some content</p>
     <someComponent [hidden]="myBoolean" class="myDirectiveClass2"></someComponent>
</div>

Existe-t-il un moyen d'y parvenir?

Merci d'avance

4
Sampgun

Voici comment je l'ai fait fonctionner

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

C'est assez simple. Je viens de vous faire un exemple.

Veuillez lire les commentaires dans la directive du chargeur.

https://github.com/garapa/studying/tree/master/loader

ÉDITER:

Votre composant:

export class LoaderComponent {

  loading;

  constructor() { }

}

Votre directive

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

}

Vous module

@NgModule({
  ...
  entryComponents: [
    LoaderComponent
  ]
})
4
Leandro Lima

Dans le fichier html du composant dans lequel le composant doit être inséré:

<div #target>
</div>

À l'intérieur du fichier ts du composant dans lequel le composant doit être inséré:

'Component_to_insert' -> est le composant à insérer dans un autre composant.

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);
    }
}
0
Kanish Mathew