63

I have a pipe that returns a html string, however the string outputs escaped presumably as a default for security. I'm sure there must be an option to allow html instead but cant find it when I search docs.

How can I tell the pipe to allow actual html to render?

rgb
  • 1,246
  • 1
  • 10
  • 14

3 Answers3

117

Use bindings to innerHTML or outerHTML to render already escaped html. For example <span [innerHTML]="someString | toHtmlPipe"></span>. See this plunk:

@Pipe({
  name: 'wrapBold'
})
class WrapBold {
  transform(content) {
    return `<b>${content}</b>`;
  }
}

@Component({
  selector: 'my-app',
  pipes: [WrapBold],
  template: `
    <div>
      Hello <span [outerHTML]="content | wrapBold"></span>
    </div>
  `
})
export class App {
  constructor() {
    this.content = 'Angular2'
  }
}
alexpods
  • 47,475
  • 10
  • 100
  • 94
  • Interesting but not quite what I wanted, I think pipes probably aren't either, what I want is to be able to have a pipe or component perhaps called "hn" when you can use it in components lets say some kind of aggregate item where I want a header element such as a `h2` but I don't want to hardcode the `h2` because I think the component should be flexible enough so if when you use it when its proceeded by a h2 rather than a h1 you can tell it to use a h3. First tried `public var hn: string = 'h3';` and then trying this in template string `<{{hn}}>` failed so I was trying other options. – rgb Dec 29 '15 at 06:35
  • thanks for the answers, they are useful for other purposes – rgb Dec 29 '15 at 06:37
  • 9
    This answers exactly what you asked for. You should either update your answer to be more precise about what you're looking for or accept it. – Eric Martinez Dec 29 '15 at 11:31
  • In case you are wondering (like I was) about the `${content}` syntax, it is a TypeScript feature: [string interpolation](https://basarat.gitbooks.io/typescript/content/docs/template-strings.html). I learn a lot from @alexpods's answers. – Mark Rajcok Dec 29 '15 at 16:57
  • 3
    @MarkRajcok Actually it's just es2015 [template strings expression interpolation](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/template_strings#Expression_interpolation) ([here](http://www.ecma-international.org/ecma-262/6.0/#sec-template-literal-lexical-components) is the spec). It's already supported by almost all major browsers (for example try to wrtte `\`Date ${Date.now()}\`` in your chrome console). – alexpods Dec 29 '15 at 17:10
  • Thanks for the correction. I'm glad I can use this without TypeScript around. – Mark Rajcok Dec 29 '15 at 17:23
  • What about pipe which returnes value but skip the possible others tags elements into it ? `

    {{ result.zip_code }}

    `The entire span tag will replace by output filtering like this...
    – Kévin Vilela Pinto Dec 05 '16 at 21:41
  • 1
    Is this answer still valid in the newer version of angular2? i cant seem to find the pipes as @component metadata, as well as i got the error Failed to set the 'outerHTML' property on 'Element': This element has no parent node. or did i missed something? – himawan_r Mar 30 '17 at 03:23
  • Using a pipe in an attribute is awesome! – Gerard Simpson Sep 18 '17 at 01:52
  • I'm also getting "Failed to set the 'outerHTML' property on 'Element': This element has no parent node." when trying to assign to [outerHTML] property with pipe output. That's disappointing, as outerHTML had also looked like a good solution for one-time binding as well. – jcairney Jan 15 '20 at 19:05
  • Actually, assigning to outerHTML probably works once in each place it's used in markup, but then every time after, when Angular runs change detection, there is an error from trying to use outerHTML again on the same element, because the element is no longer attached to the DOM at that point. – jcairney Jan 15 '20 at 19:14
14

I don't know if that is possible with a pipe. (It is, see @alexpods's answer.)

Have you considered converting your pipe into a component with an input property? I.e., whatever is feeding your pipe, make that an input property of the component. Put the HTML that the pipe generates into the component's template.

Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • 1
    I think this is the correct way of tackle this problem. Pipes are not the solution to modify html. – Jesus Jan 17 '20 at 15:23
  • 1
    @Jesus There are legit reasons to do it (though the OP's use case doesn't fall under it). A simple example would be a "highlight" pipe, where you output some text with subsets highlighted based on what the user has searched for. Pipe's aren't a bad solution, and the only practical way to do this is to inject styled tags within the text, thus the need for outputting html. – riwalk Jul 11 '22 at 16:37
12

So thanks for replies.

Using the outerHTML binding suggested by @alexpods worked a treat. Didn't need to change my pipe at all.

So what I was doing before:

{{'TEXT' | hn: 'h2.whatever'}} which resulted in the correct html but escaped ie.

&lt;h2 class="whatever"&gt;TEXT&lt;/h2&gt;

Works great as: <span [outerHTML]="'TEXT' | hn:'h2.whatever'"></span>

which outputs: <h2 class="whatever">TEXT</h2>

rgb
  • 1,246
  • 1
  • 10
  • 14
  • 2
    Spoke to soon... It works however only the first time, if you are updating the view for example a menu that updates detail, the next time round it will fail with the following error "Failed to set the 'outerHTML' property on 'Element': This element has no parent node" presumably because of the previous transformation. – rgb Dec 31 '15 at 01:26
  • I think you need to set `pure: false` for your pipe. – Günter Zöchbauer Dec 31 '15 at 08:09
  • 2
    I had the same issue, and I fixed it by changing `span` to `div` and using `innerHTML` instead of `outerHTML`, so for your example: `
    `
    – crollywood Oct 07 '17 at 10:22