3

After much searching I am trying to find a simple way to execute a method when clicking a link in dynamically created HTML that is being saved in a database. I'm creating messages to users about transactions that have various links embedded in the message body. I need to save the message on the database and when retrieved and viewed, the user should be able to click a link to call a method which will route them to the proper page.

The HTML looks something like this:

"string myHTML='<div><a (click)=method1(tranID)>Execute Method 1></a><div>
<br><br>
<div><a (click)=method2(tranID)>Execute Method 2></a><div>'

In my HTML file I have:

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

I understand that this is by design in Angular but there has to be a reasonably straightforward way to do this. I am not an Angular expert and need some help! Thanks

Lex
  • 6,758
  • 2
  • 27
  • 42
Matt K
  • 61
  • 1
  • 7
  • So what is the problem? Does the function not execute? – callback Mar 26 '18 at 16:30
  • 4
    This is analogous to a SQL Injection attack. By giving you the ability to do this, you would be simultaneously giving people the potential ability to exploit your site by adding unexpected code into data being saved. Bottom line, ***don't ever save functions as user data***. Find a different way to store the data and construct the HTML from the data on demand. – Claies Mar 26 '18 at 16:31
  • You can't call an angular component method from outside of the Angular scope (ie: a dynamically created html) . This is as @Claies said a design mistake, try with another more safe database design. – Mehdi Benmoha Mar 26 '18 at 16:36
  • @callback - correct. Functions do not execute – Matt K Mar 26 '18 at 17:26
  • @Claies - Actually want to store page routes. Not functions. – Matt K Mar 26 '18 at 17:27
  • well a route from outside the app is just a plain URL. You are trying to store a click method that would be evaluated by angular, not a URL that would come in from the outside. You are not storing a page route, you are storing a command (function call). – Claies Mar 26 '18 at 17:29
  • if you want to send the user a message that has a link that routes them to a page, then you should pre-evaluate the expected result, and save this result URL as an `href="yoursite.com/someroute"` rather than a `click` method. – Claies Mar 26 '18 at 17:35
  • storing HTML inside database values / JavaScript Object Properties is a practice that should be avoided completely if possible, and only ever be considered in cases of storing user created HTML. Since you should never expect the user to know the internals of your app design, you should also assume this stored HTML would not know how to make function calls. In your own code, there is never a good reason to store HTML, since Components / Templates can **always** be used to construct your DOM from data elements. – Claies Mar 26 '18 at 17:40
  • I don't want to reload the app with a url call...I want to do – Matt K Mar 26 '18 at 17:46
  • So I'm asking how to create Components/Templates from data elements to get that behavior – Matt K Mar 26 '18 at 17:47
  • You would start with creating a component that has the HTML structure you want, and then passing your data in to the component, instead of using `[innerHTML]` – Claies Mar 26 '18 at 17:50
  • Thanks for your time @Claies – Matt K Mar 26 '18 at 17:58

1 Answers1

8

Assuming your html has links like <a href="/home">home</a>, you can bind the (click) event on the container and catch any bubbled clicks from the dynamically added elemens inside:

<div (click)="click($event)" [innerHTML]="html"></div>

click(evt) {
   const href = evt.target.getAttribute('href');
   if (href) {
      evt.preventDefault();
      this.router.navigate(href);
   }
}
funkizer
  • 4,626
  • 1
  • 18
  • 20
  • This did it! Thank you! – Matt K Mar 26 '18 at 18:39
  • Great, np! Edited the answer to just show the (click) way, as I think it's cleanest :) – funkizer Mar 26 '18 at 21:35
  • Having another problem with this: When the page initially loads with the dynamic HTML, the click event does not fire. If I reload the page using the browser reload (using Chrome) starts to work and continues to work even if I enter the page with different data. – Matt K Mar 27 '18 at 15:20
  • Weird! Hmm. Try *ngIf="html" on the div. Set this.html=null when you start loading the html. Maybe it helps if the container is initialized only when the html is loaded. – funkizer Mar 27 '18 at 15:31
  • This didn't work. I assume that the code is not compiled and that the reload compiles it? – Matt K Mar 27 '18 at 16:15