mdev
mdev

Reputation: 43

Whats the Angular way of cloning/moving an element into the body with all event listeners?

For example i have something like this:

FancyComponentWantsToShowAnOverlay.ts

  ...
  ClickToDoSomething(): void {
    // doing something
  }

  MoveOrCloneToBody(): void {
    // do the magic
  }
  ...

FancyComponentWantsToShowAnOverlay.html ...

* displaying fancy stuff *

<ng-template #MoveOrCloneMeToBodyPlease>
  * seriously beautiful stuff will be displayed here *
</ng-template>

* displaying more fancy stuff *
<a (click)="MoveOrCloneToBody()">do the magic</a>

MoveOrCloneMeToBodyPlease should be appended to body (removing also would be nice later).

Thanks!

Upvotes: 1

Views: 1989

Answers (1)

H3AR7B3A7
H3AR7B3A7

Reputation: 5261

Dynamically Add/Remove Html Elements

*ngFor

You can create a component of the 'something beautiful' and use the ngFor directive to loop over an array which you can add or remove elements to/from. All the eventlisteners would be in the components that are added.

Template:

<app-some *ngFor="let color of colors"></app-some>

Script:

export class AppComponent  {
  colors = [{}]

  addColor() {
    this.colors.push({})
  }

  removeColor() {
    this.colors.pop()
  }
}

Here is an example in a Stackblitz

Renderer2

You can also use renderer2 to manipulate the DOM, where you can bind to the element you want to append children to using @ViewChild annotation. You can add listeners to elements using renderer2, so this would also fit your purpose.

Template:

<div #container></div>

Script:

export class AppComponent  {

  @ViewChild("container")
  el: ElementRef

  children = []

  constructor(private renderer: Renderer2) {}

  createSOmethingBeautiful() {
    let div = this.renderer.createElement('div')
    let text = this.renderer.createText('Beautiful stuff');
    this.renderer.appendChild(div, text);
    this.children.push(div)
    return div
  }

  add() {
    this.renderer.appendChild(this.el.nativeElement, this.createSOmethingBeautiful())
  }

  remove() {
    this.renderer.removeChild(this.el.nativeElement, this.children.pop())
  }
}

Here is another example in a Stackblitz.

InnerHTML

You can also bind to the innerHtml from any html element. But, this would not contain any eventlisteners so wouldn't solve your problem.

Template:

<div [innerHTML]="html"></div>

Script:

export class AppComponent {
  private _html = [''];

  get html () {
    return this._html.join('')
  }

  add() {
    this._html.push('<p>Something pretty</p>')
  }

  remove() {
    this._html.pop()
  }
}

And yet another example in a Stackblitz.

Upvotes: 2

Related Questions