Reputation: 35
I have a pipe that replaces the text links with html links and I put the link in a paragraph with [innerHtml]. The problem with innerHTML is that if someone types something like "a<b?" or anything containing the characters "<" or ">" all the text that follows it is not displayed
< p [innerHTML]="text | generateLinksPipe">
this is the pipe:
export class GenerateLinksPipe implements PipeTransform { transform(value: string, aClass?:string ): string {
// http://, https://, ftp://
const urlPattern = /\b(?:https?|ftp):\/\/[()a-z0-9-+*&@+#\/%?=+_~_|!:,.;]*[a-z0-9-+&@#\/%=_~_|]/gim;
// www. sans http:// or https://
var pseudoUrlPattern = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
// Email addresses
var emailAddressPattern = /^[a-zA-Z0-9.!#$%&'*+=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*/;
return value
.replace(urlPattern, `<a href="$&" target="_blank">$&</a>`)
.replace(pseudoUrlPattern, `$1<a href="http://$2" target="_blank">$2</a>`)
.replace(emailAddressPattern, `<a href="mailto:$&" target="_blank" >$&</a>`);
} }
I need a way to display the links in the paragraph but be able to use the "<" and ">" characters without any problems.
Upvotes: 1
Views: 405
Reputation: 19764
It's a wrong approach to generate HTML when using Angular. The whole idea behind Angular is that you stop thinking about "how to manipulate HTML"; instead, we have a model and we define how this models maps to the view -- this is your Angular template.
Instead of performing the operation on string and getting HTML
foo www.bar.com baz => foo <a href="#">bar</a> baz
you should perform an operation which gives you the model of your text.
foo www.bar.com baz => [ { type: 'text', value: 'foo ' },
{ type: 'link', href: '#', value: 'www.baz.com' },
{ type: 'text', value: ' baz' } ]
This is objectively a better approach because it separates your business logic (what is a link?) with the representation/view layer (how do I want to represent it). You can now build HTML, XHTML, Markdown, or whatever you want from it. It also saves you from the issue you described (what if the string already contains HTML-specific characters).
What you need here is an Angular template based on this model. Note that Angular template is not HTML! When you write a template in Angular, the compiler (ngc
) will transform that string (your template) into a series of JavaScript functions which manipulate DOM.
To create what you need, you can do the following.
<ng-container *ngFor="let chunk of parsedData">
<ng-container [ngSwitch]="chunk.type">
<ng-container *ngSwitchCase="'text'">{{ chunk.value }}</ng-container>
<a *ngSwitchCase="'link'" [href]="chunk.href">{{ chunk.value }}</a>
</ng-container>
</ng-container>
Upvotes: 0