简体   繁体   中英

How can I trigger a click event on element generated dynamically in angular 4?

I am using an API get call to fetch the HTML code from database and render the html.

The generated HTML is as below: -

<span (click)="triggerClick()" data-link-id="960" data-link="8" class="level_modal">individuals</span>

triggerClick() function is defined in the ts file but the same is not triggered with dynamically generated html code.

Reason

It's not going to work. The language you use to write Angular templates in is not HTML. It's a custom Angular syntax that purposely looks like HTML to make experience of writing code better. Those templates are then compiled into highly optimized JavaScript functions.

A string you get from your API is received during the run-time of your application, which means that Angular's compiler has already done its job (it has compiled the code which is why you can run your application at all). At this point, Angular's compiler is not available anymore by default. Including the compiler in the final bundle of your app is a performance issue because the compiler code has a large size footprint. This is the reason why AOT compilation (ahead of time) is the default and recommended way of publishing Angular apps for production.

Solution

Your API should not return HTML at all. The whole idea behind single page applications (SPA) is for them to consume and API which is language- and platform-agnostic. It simply works with data , which is today mostly encoded via JSON notation. It's the only language API is supposed to understand.

From what I can gather from the code example you've posted here, you're interested in data of this form:

{ linkId: 960,
  link: 8,
  text: individuals }

Create an API endpoint which returns data in this form, and then use Angular to loop over the data and create the template which you need.

<span *ngFor="let item of items"
       (click)="triggerClick()"
       [attr.data-link-id]="item.linkId"
       [attr.data-link]="item.link"
       class="level_modal">
  {{ item.text }}
</span>

Of course, you probably do not need all those data- attributes anyway. This is because Angular application should focus on the model. Model is the source of truth which is used to create the template. If you need additional information about each item (such as link and linkId ), just keep in the memory as an object. No need to encode it into HTML just to read it later again.

When you write

(click)="doSomething()"

You want to say

Launch the method doSomething when I click on this

But what you actually say is

Please Angular, compile this code so that when I click on this, it launches doSomething

Because as you may know, you're writing Typescript, not Javascript. So your code will be compiled to be served, thus transforming this into

onclick="doSomething()"

BUT WAIT, THERE'S MORE

When you compile your code, it's actually minified and uglified. So this will give you something along the lines of

onclick="a()"

And thus, making you lose any logic behind this.

So what's the solution ?

The solution is to bind the click event to a global function. There's two ways of doing this :

  • Function in your component ( use it if you want to use logic from your component )
  • Global function ( use it if you want this function to be called in several components )

I'll explain the first use-case, for the second I'll make it short : create a JS file as an asset, put your function in it, and call it on click.

For the second one, it's a bit tricky.

First, inject ngZone into your component : this allows you to handle code outside of Angular

constructor(private zone: NgZone) {}

Then, create a global function (I'll make it Typescript and linting compliant)

ngOnInit() {
  this.zone.run(() => {
    window['doSomething'] = () => {
      console.log('Look mom, I did something !');
    };
  });
}

After this, delete the function once you leave the component

ngOnDestroy() { delete(window['doSomething']); }

Finally, change your HTML from this

(click)="doSomething()"

To this

onclick="window.doSomething()"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM