9

I'm learning angular via youtube, but I'm trying to do something new, and I'm getting an error on that, my code is attached below, help me out.

I want to setAttribute like this div.setAttribute('(click)',"popUp($event)"); but I got error.

TypeScript

export class AppComponent {
    createEl(){
      console.time("timer");
      for (let i = 0; i < 10; i++) {
        let div = document.createElement("div");
        div.textContent = `Hello, World! ${i}`;
        div.setAttribute('(click)',"popUp($event)");
        document.getElementById('divEl')?.appendChild(div);
      };
      console.timeEnd("timer");
}

HTML

<div id="divEl"></div>
<button (click)="createEl()">click me</button>

Error

my Error photo

R. Richards
  • 24,603
  • 10
  • 64
  • 64

6 Answers6

13

This is not really the angular way of doing things. Try to avoid operations on document such as document.createElement.

A better way to achieve this would be to define what the repeating element would look like in the template and drive it from an array. That way we can keep the template doing display and the typescript doing processing, and Angular handling everything in between.

HTML

<div id="divEl">
  <div *ngFor="let row of rows; index as i;" (click)="popUp($event)">
    Hello, World! {{i}}
  </div>
</div>

<button (click)="createEl()">click me</button>

Typescript

export class AppComponent {
  rows: unknown[] = [];
  createEl():void {
    this.rows.push('something');
  }

  popUp(event:Event):void {}
}  

More reading on loops: https://angular.io/api/common/NgForOf

Calummm
  • 819
  • 1
  • 8
  • 21
  • that takes more time than typescript append you can check it. – Logwin Finserv Jul 23 '21 at 03:51
  • 3
    What takes more time, execution time or code writing? Either way, this is the appropriate way to structure template updates in angular – Calummm Jul 24 '21 at 09:39
  • 2
    It is still the appropriate way to do it in Angular. Yes the execution time may be slower in this example, but when you start utilising other Angular template features the overhead is not additive. – Calummm Jul 27 '21 at 03:14
  • 1
    To improve upon this answer (that is the correct way to utilize the framework), you can use a `trackBy` function to improve ngFor Rendering performance. Like this `*ngFor="let row of rows; index as i; trackBy: myTrackBy”`. Then in the TS do: `myTrackBy(item, index:number) { return item.idProp}` – Ben L Sep 05 '21 at 18:31
  • 1
    To add to this, it's not just about time, it's about security. A large chunk of the benefit to using Angular is that it shoulders the burden of manipulating the DOM for you. Otherwise, every time you do direct DOM manipulation in Angular, you need to trace back whatever variables contribute to your DOM manipulations, to make sure they never come from any sort of user input (and no future changes will ever make this the case -- a tall order). Why? Security, in a way somewhat similar to SQL injection (conceptually). Primarily b/c of server-side rendering. – acat Sep 05 '21 at 19:49
  • 1
    Be careful about the signature of `TrackByFunction` - the order is actually the other way around, e.g. `*ngFor="let row of rows; trackBy: myTrackBy"`, and in the template, it is `myTrackBy(index: number, item: T)` with whatever type `T` the element has. – evilstiefel Sep 07 '21 at 06:35
4

That's right check below.

div.addEventListener('click', (e) => {
  this.popUp(e);
});
Brijesh Kalkani
  • 789
  • 10
  • 27
2

Problem is you are trying to do angular stuff with pure javascript.

<div (click)="method()"> is angular. In javascript you'd do someting like this <button onclick="myFunction()">Click me</button> Other options are to use event handlers https://www.w3schools.com/js/js_htmldom_eventlistener.asp

Anyhow, angular doesn't recommend changes the DOM because then it won't recognize those changes. Here are multiple examples ho to properly change the dom

Robin Dijkhof
  • 18,665
  • 11
  • 65
  • 116
1

You can set the click event as shown below instead of using setAttribute

div.addEventListener('click', (e) => {
  this.popUp(e);
});
laiju
  • 1,353
  • 10
  • 17
1

(click) is not an html attribute, it is Angular event binding syntax

This syntax consists of a target event name within parentheses to the left of an equal sign, and a quoted template statement to the right.

You cannot use that with JavaScript. Use

div.onclick = popUp;
naveen
  • 53,448
  • 46
  • 161
  • 251
0
export class AppComponent {
    createEl(){
      console.time("timer");
      for (let i = 0; i < 10; i++) {
        let div = document.createElement("div");
        div.textContent = `Hello, World! ${i}`;

        div.addEventListener('click', (e) => {
          this.popUp(e);
        });

        document.getElementById('divEl')?.appendChild(div);
      };
      console.timeEnd("timer");
}
Craig
  • 11
  • 1