Clone a div with renderer 2 and angular

386 Views Asked by At

Good morning, I am having a problem with viewchild which cannot find my selector in my html code. The goal is to look for my 'field' selector in my html to clone it and add a new class to it each time a button is clicked. To do this I wanted to use renderer 2. Here is my html code:

<ng-template #effacer4>
  <div *ngIf="Next3"><div #Champ>
  <div class="Champ" [ngClass]="Champ">
      <h1 class="title"> Prêt(s) immobilier à assurer </h1><br>
      
      <h2>Type de prêt</h2>
        <select class="form-select" aria-label="Default select example">
          <option value="1">Prêt classique (amortissable)</option>
          <option value="2">In fine</option>
          <option value="3">Prêt à taux Zéro</option>
          <option value="4">Prêt relais</option>
        </select> <br>
        <h2>Montant du prêt</h2>
        <div class="input-group mb-3">
          <input type="text" class="form-control" aria-label="Amount (to the nearest dollar)">
          <span class="input-group-text">.00 €</span>
        </div>
        <h2>Taux du prêt</h2>
        <div class="input-group mb-3">
          <input type="text" class="form-control" aria-label="Amount (to the nearest dollar)">
          <span class="input-group-text">%</span>
        </div>
  
    <h2>Durée totale</h2>
        <div class="input-group mb-3">
          <input type="text" class="form-control" aria-label="Amount (to the nearest dollar)">
          <span class="input-group-text">an(s)</span>
          <input type="text" class="form-control" aria-label="Amount (to the nearest dollar)">
          <span class="input-group-text">mois</span>
        </div>
        <h2>Dont différé</h2>
        <select class="form-select" aria-label="Default select example">
          <option value="1">1 mois</option>
          <option value="2">2 mois</option>
          <option value="3">3 mois</option>
          <option value="4">4 mois</option>
          <option value="5">5 mois</option>
          <option value="6">6 mois</option>
          <option value="7">7 mois</option>
          <option value="8">8 mois</option>
          <option value="9">9 mois</option>
          <option value="10">10 mois</option>
          <option value="11">11 mois</option>
          <option value="12">12 mois</option>
          <option value="13">13 mois</option>
          <option value="14">14 mois</option>
          <option value="15">15 mois</option>
          <option value="16">16 mois</option>
          <option value="17">17 mois</option>
          <option value="18">18 mois</option>
          <option value="19">19 mois</option>
          <option value="20">20 mois</option>
          <option value="21">21 mois</option>
          <option value="22">22 mois</option>
          <option value="23">23 mois</option>
          <option value="24">24 mois</option>
        </select>
       </div>
      </div></div>
<button (click)="Clone()"class="btn btn-secondary btn-lg"><fa-icon [icon]="faPlusSquare"></fa-icon>  Ajouter un prêt à assurer</button>
</ng-template>

and typescript:

import { Component,ViewChild, ElementRef,Renderer2,AfterViewInit  } from '@angular/core';
import {faFileContract,faChartLine,faCalculator,faBuilding,faHome,faMapMarkedAlt,faChess,faChessKing,faPlusSquare } from '@fortawesome/free-solid-svg-icons';

@Component({
  selector: 'app-questionnaire',
  templateUrl: './questionnaire.component.html',
  styleUrls: ['./questionnaire.component.css'],  
})

export class QuestionnaireComponent implements AfterViewInit{
  faFileContract=faFileContract;
  faChartLine=faChartLine;
  faCalculator=faCalculator;
  faBuilding=faBuilding;
  faHome=faHome;
  faMapMarkedAlt=faMapMarkedAlt;
  faChessKing=faChessKing;
  faChess=faChess;
  faPlusSquare=faPlusSquare;
  button: boolean = true;
  SUIVANT:boolean=true;
  Next:boolean=true;
  Next2:boolean=true;
  Next3:boolean=true;
  dynamic=0;
  Champ!: HTMLDivElement;
  
  @ViewChild('Champ')ChampViewChild!: ElementRef;
  
  constructor(private _renderer: Renderer2) {}

  Clone() {
    console.log("Button clicked!");
    this._renderer.addClass(this.ChampViewChild.nativeElement, 'Champ');
    let clonedChamp = this._renderer.createElement(this.ChampViewChild.nativeElement.tagName);
    this._renderer.addClass(clonedChamp, 'Champ');
    this._renderer.appendChild(this.ChampViewChild.nativeElement, clonedChamp);
  }
  
  ngAfterViewInit() {
    if (this.ChampViewChild) {
      this.Clone();
    }
  }
  incrementProgress() {
    this.dynamic += 5;
  };

}

No code error is indicated in my terminal..

1

There are 1 best solutions below

0
Jordi Riera On

The way I would approach this would be by creating a viewContainerRef (which is where the elements would be cloned into.

Then create a view from the TemplateRef via createEmbeddedView and insert this view into the viewContainerRef

<div>
    <ng-container #champContainer></ng-container>
</div>
<ng-template #champ>Your html in here</ng-template>
<button (click)="addDynamicHTML()">Add HTML</button>

inside the .ts file of the component something like this:

  @ViewChild('champContainer', {read:ViewContainerRef}) champContainer

  @ViewChild('champ',{read:TemplateRef}) champ

.....

addDynamicHTML(){

  
    //creates a view from the #champ templateRef 

    const view = this.champ.createEmbeddedView()
    //inserts the view created inside the
    this.champContainer.insert(view)
  }

Also be aware that the createEmbeddedView() method allows for parameters which can give you even greater flexibility in the way you create the new elements(probably how you could tackle the new class for the element). This is not an exhaustive copy/paste code but it is a good approximate of how I would approach this development