TransWikia.com

Angular/Typescript Text with routerLink

Stack Overflow Asked by Dotnet on December 11, 2021

Updated Question for more Clarity:

Need to display some texts and links as innerHTML(data from service/DB) in the Angular HTML and when user clicks, it should go to Typescript and programmatically navigates by router.navigate

Also, How to add DomSanitizer from @ViewChild/ElementRef

Added all example in below code

Here is the updated stackblitz code

As shown in screenshot from angular.io some texts and some links

enter image description here

2 Answers

Sorry, I didn't realize you answered my comment. Angular routing is not secondary, if you don't use Angular modules you'll end up with just an HTML/CSS/Typescript application. you need at least the RouterModule for Angular to be able to use routing and hence, do what it's supposed to with the DOM.

First:

  • You are not importing RouterModule

    solution:

    imports: [ 
      BrowserModule, 
      FormsModule, 
      RouterModule.forRoot([])  // this one
    ]
    

Second:

  • You can't bind Angular events through innerHTML property

    fix:

Make use of @ViewChild directive to change your innerHTML property and manually bind to the click event, so change in your app.component.html from

<div id="box" [innerHTML]="shouldbedivcontent" ></div>

to

<div #box id="box"></div>

Now, in your app.component.ts, add a property to hold a reference to that "box" element so you can later make some changes to the dom with it:

  @ViewChild('box')  container: ElementRef;

Implement AfterViewInit, that hook is where you will be able to actually handle your container, if you try using it for example in OnInit you'd get undefined because that component's html is not in the dom yet.

export class AppComponent  implements AfterViewInit {

and

ngAfterViewInit() {
    this.container.nativeElement.innerHTML = this.shouldbedivcontent;
    this.container.nativeElement.addEventListener('click', 
      () => this.goto('bar')
    );
}

change shouldbedivcontent property from:

'1) this is a click 
 <a (click)="goto("bar")">Click</a><br> 
 2)this is with routerlink 
 <a routerLink="" (click)="goto("bar")">Click</a><br> 
 3)This only works with href 
 <a href="goto/bar" title="bar">bar</a>&nbsp; and test'

to

'1) this is a click 
 <a id="link_1">Click</a><br> 
 2)this is with routerlink 
 <a [routerLink]="" (click)="goto('bar')">Click</a><br> 
 3)This only works with href 
 <a href="goto/bar" title="bar">bar</a>&nbsp; and test'

And even so you'd still not get the default anchor style unless you apply some styling yourself.

Third

You are not HTML sanitizing, which could be dangerous. read more here

MY SUGGESTION:

Seems like a lot to do for you and a lot to read for someone else working alongside you for something you could easily do like in the example below!

Move your html to your app.component.html:

<div id="box">
  1) this is a click 
  <a (click)="goto('bar')">Click</a><br> 
  2)this is with routerlink 
  <a routerLink="" (click)="goto('bar')">Click</a><br> 
  3)This only works with href 
  <a href="goto/bar" title="bar">bar</a>&nbsp; and test
</div>

<p>Below is actual content</p>

You'll notice that everything works now, except the anchor without routerLink or href, because that's not a link.

EDIT:

Looking at the new stackblitz, i suggest a change of approach, binding to innerHTML is ok when working with plain text or even some simple html but not a great choice to bind events or routing logic.

Angular's Renderer2 provides with a bunch of methods to dyncamically add elements to the DOM. With that on the table, you just need a little effort to take that simple html you get from your backend and turn it into something like (paste this property in your code to test it along the rest of the code provided below):

public jsonHTML = [
  {
    tagName: '',
    text: 'some text with click ',
    attributes: {
    }
  },
  {
    tagName: 'a',
    text: 'bar',
    attributes: {
      value: 'bar' // goto parameter
    }
  },
  {
    tagName: '',
    text: ' some more text with click ',
    attributes: {
    }
  },
  {
    tagName: 'a',
    text: 'foo',
    attributes: {
      value: 'foo' // goto parameter
    }
  }
]

Once you have it, it's way easier to create all of those elements dynamically:

this is for the code in your Q1:

Inject Renderer2 with private r2: Renderer2

And replace the Q1 related code in AfterViewInit hook to:

const parent = this.r2.createElement('div');  // container div to our stuff

this.jsonHTML.forEach((element) => {
  const attributes = Object.keys(element.attributes);
  const el = element.tagName && this.r2.createElement(element.tagName);
  const text = this.r2.createText(element.text);

  if (!el) {  // when there's no tag to create we just create text directly into the div.
    this.r2.appendChild(
      parent,
      text
    );
  } else { // otherwise we create it inside <a></a>
    this.r2.appendChild(
      el,
      text
    );

    this.r2.appendChild(
      parent,
      el
    );
  }
  
  if (attributes.length > 0) {
    attributes.forEach((name) => {
      if (el) {
        this.r2.setAttribute(el, name, element.attributes[name]); // just the value attribute for now

       if (name === 'value') { 
          this.r2.listen(el, 'click', () => {
            this.goto(element.attributes[name]); // event binding with property "value" as parameter to navigate to
          })
        }
      } else {
        throw new Error('no html tag specified as element...');
      }
    })
  }
})

this.r2.appendChild(this.container.nativeElement, parent); // div added to the DOM

No html sanitizer needed and no need to use routerLink either just inject Router and navigate to the route you want! Make improvements to the code t make it fit your needs, it should be at least a good starting point

Good Luck!

Answered by Alejandro Camba on December 11, 2021

You have a css problem.

  1. <a href="something"></a> looks like a link
  2. <a [routerLink]="something"></a> looks like a link, because if you inspect the HTML it actually gets an href property added because of routerLink
  3. <a (click)="goTo()"></a> does NOT look like a link, because there is no href

Chrome and Safari default user agents css will not style <a> without an href (haven't confirmed Firefox but I'm sure its likely). Same thing for frameworks like bootstrap.

Updated stackblitz with CSS moved to global, not app.css https://stackblitz.com/edit/angular-ivy-kkgmkc?embed=1&file=src/styles.css

This will style all links as the default blue, or -webkit-link if that browser supports it. It should be in your global.css file if you want it to work through the whole app.

a {
  color: rgb(0, 0, 238);
  color: -webkit-link;
  cursor: pointer;
  text-decoration: underline;
}

Answered by cjd82187 on December 11, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP