-1

I'm looking for the best (or at least good) practice for a particular case.

I'm making a small Angular app where users can add text. I want them to be able to put some words in bold or create links really simply. So for example, when they type *whatever* it should be bold. So for now what I'm doing is :

  • Get the text
  • Transform it with a js function (so now my string is <b>whatever</b>)
  • And call it in my html with [innerHTML]

The thing is I don't want them to be able to write whatever html they want. Is there a way to avoid using [innerHTML] in this case ?

Thank you for your time.

Unpuzz
  • 11
  • 4
  • You might consider using something like [ngx-markdown](https://github.com/jfcere/ngx-markdown) – abney317 Dec 03 '19 at 15:54
  • Actually I already consider it (I should have tell it) but it's much more than I need, and for the "links part" I have to make the links with a default path – Unpuzz Dec 03 '19 at 15:57

1 Answers1

1

Allowing users to enter arbitrary text and displaying it with innerHTML is dangerous and really requires you to know what you're doing.

I'd say your safest option here (without using innerHTML) is to create a component that parses the string, breaks it into segments with their types and content, and dynamically places template, like:

<ng-container *ngFor="let segment of segments">
  <span [ngSwitch]="segment.type">
    <ng-container *ngSwitchCase="'bold'"><b>segment.content</b></ng-container>
    <ng-container *ngSwitchCase="'link'"><a [href]="segment.data">segment.content</a></ng-container>
    <ng-container *ngSwitchDefault>segment.content</ng-container>
  </span>
</ng-container>

This template could be expanded to handle italics, underline, or whatever. There are some issues with it (like handling anything nested or multiple tags) but all should be solvable.

your segment model might look like:

interface Segment {
  content: string;
  type: 'bold'|'text'|'link';
  data?: any;
}

and then you need some function that parses your string into these segments. hard to say what your parse function would look like without knowing more about your case, but hopefully this gets you started

a posibly easier and still very safe secondary option is to sanitize or escape your string prior to inserting your own tags based on your custom marks, this way you can safely use innerHTML:

// inject the sanitizer
constructor(private sanitizer: DomSanitizer){ }

// run this on your string to remove unsafe text, then insert your marks so you can safely use innerHTML
sanitize(text: string) {
  return this.sanitizer.sanitize(SecurityContext.HTML, text);
}

the sanitizer will actually remove unsafe text, though if you want to keep it and display it as text, you could also escape it like in this question here: Manually sanitize a string

bryan60
  • 28,215
  • 4
  • 48
  • 65