10

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

6 Answers 6

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

Sign up to request clarification or add additional context in comments.

6 Comments

What takes more time, execution time or code writing? Either way, this is the appropriate way to structure template updates in angular
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.
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}
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.
Be careful about the signature of TrackByFunction<T> - 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.
|
4

That's right check below.

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

Comments

2
+25

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

Comments

1

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

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

Comments

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;

Comments

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

1 Comment

Please add further details to expand on your answer, such as working code or documentation citations.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.