简体   繁体   English

如何在角度4中动态生成的元素上触发click事件?

[英]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. 我正在使用API​​ get调用从数据库中获取HTML代码并呈现html。

The generated HTML is as below: - 生成的HTML如下: -

<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. triggerClick()函数在ts文件中定义,但动态生成的html代码不会触发相同的函数。

Reason 原因

It's not going to work. 它不会起作用。 The language you use to write Angular templates in is not HTML. 用于编写Angular模板的语言不是HTML。 It's a custom Angular syntax that purposely looks like HTML to make experience of writing code better. 这是一个自定义的Angular语法,有意地看起来像HTML,可以更好地编写代码。 Those templates are then compiled into highly optimized JavaScript functions. 然后将这些模板编译为高度优化的JavaScript函数。

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). 在应用程序运行期间收到从API获得的字符串,这意味着Angular的编译器已经完成了它的工作(它编译了代码,这就是为什么你可以运行你的应用程序)。 At this point, Angular's compiler is not available anymore by default. 此时,Angular的编译器默认不再可用。 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. 这就是为什么AOT编译(提前)是为生产发布Angular应用程序的默认和推荐方式的原因。

Solution

Your API should not return HTML at all. 您的API根本不应返回HTML。 The whole idea behind single page applications (SPA) is for them to consume and API which is language- and platform-agnostic. 单页面应用程序(SPA)背后的整个想法是供他们使用,以及与语言和平台无关的API。 It simply works with data , which is today mostly encoded via JSON notation. 它只适用于数据 ,现在大多数都是通过JSON表示法编码的。 It's the only language API is supposed to understand. 这是API应该理解的唯一语言。

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. 创建一个以此形式返回数据的API端点,然后使用Angular循环数据并创建所需的模板。

<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. 当然,您可能无论如何都不需要所有这些data-属性。 This is because Angular application should focus on the model. 这是因为Angular应用程序应该关注模型。 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. 如果您需要有关每个项目的其他信息(例如linklinkId ),请将内存作为对象保留。 No need to encode it into HTML just to read it later again. 无需将其编码为HTML只是为了以后再读它。

When you write 当你写作

(click)="doSomething()"

You want to say 你想说

Launch the method doSomething when I click on this 单击此按钮时启动方法doSomething

But what you actually say is 但你实际上说的是

Please Angular, compile this code so that when I click on this, it launches doSomething 请Angular,编译这段代码,这样当我点击它时,它会启动doSomething

Because as you may know, you're writing Typescript, not Javascript. 因为您可能知道,您正在编写Typescript,而不是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. 解决方案是将click事件绑定到全局函数。 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. 我将解释第一个用例,对于第二个用例,我将简要说明:创建一个JS文件作为资产,将您的函数放入其中,然后单击调用它。

For the second one, it's a bit tricky. 对于第二个,它有点棘手。

First, inject ngZone into your component : this allows you to handle code outside of Angular 首先,将ngZone注入组件:这允许您处理Angular之外的代码

constructor(private zone: NgZone) {}

Then, create a global function (I'll make it Typescript and linting compliant) 然后,创建一个全局函数(我会使它成为Typescript和linting)

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 最后,从中更改HTML

(click)="doSomething()"

To this 对此

onclick="window.doSomething()"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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