앵귤러 템플릿에서 innerHTML과 DomSanitizer를 사용하는 방법

2 분 소요

블로그 앱에서 tinymce 같은 플러그인으로 작성한 글은 HTML 코드 형태로 데이터베이스에 저장됩니다. 이 데이터를 앵귤러 템플릿에서 다시 렌더링하는 방법을 정리합니다.

데이터베이스에 저장된 HTML 코드가 아래와 같다고 가정합니다.

<h1><span style="color: #f1c40f;">안녕하세요. 이상희입니다.</span></h1>

가장 흔한 실수는 아래와 같이 HTML 코드를 태그 안에 그대로 삽입하는 방식입니다.

<div class="post-content">{{ post.content }}</div>

이렇게 작성하면 아래 이미지처럼 HTML 코드가 일반 텍스트로 그대로 출력됩니다.

HTML 코드가 그대로 출력되는 문제
HTML 코드가 그대로 출력되는 문제

이 문제는 아래와 같이 innerHTML 속성 바인딩(property binding)을 사용해 해결할 수 있습니다.

<div class="post-content" [innerHTML]="post.content"></div>
인라인 스타일이 사라지는 문제 발생
인라인 스타일이 사라지는 문제 발생

HTML 코드는 정상적으로 렌더링되지만 또 다른 문제가 있습니다. 개발자 도구로 실제 적용된 코드를 살펴보면 아래와 같이 span 태그에 포함되어 있던 인라인 CSS 스타일이 사라져 있습니다.

개발자 툴에서 코드 확인
개발자 툴에서 코드 확인

이 동작은 앵귤러가 위험한 HTML 코드의 삽입을 차단하기 위해 제공하는 기본 보호 장치 때문에 발생합니다. 신뢰 가능한 콘텐츠임을 명시해야 하며, 앵귤러가 제공하는 DomSanitizer 클래스로 간단히 처리할 수 있습니다.

먼저 템플릿에서 사용할 파이프 클래스를 생성합니다.

$ ng g pipe trust-html

trust-html.pipe.ts가 생성되면 아래와 같이 수정합니다.

trust-html.pipe.ts
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';

@Pipe({
  name: 'trustHtml'
})
export class TrustHtmlPipe implements PipeTransform {

  constructor(private sanitizer: DomSanitizer) {
  }

  transform(content): unknown {
    return this.sanitizer.bypassSecurityTrustHtml(content);
  }
}

app.module.tsdeclarations에 등록하는 것도 잊지 말아야 합니다.

app.module.ts
import { TrustHtmlPipe } from './pipes/trust-html.pipe';

@NgModule({
  declarations: [
    AppComponent,
    ... 생략 ...
    TrustHtmlPipe,
  ],

생성한 파이프를 템플릿에서 사용하면 다음과 같습니다.

<div class="post-content" [innerHTML]="post.content | trustHtml"></div>
정상적으로 출력되는 경우
정상적으로 출력되는 경우

이상으로 innerHTML 속성 바인딩과 파이프(pipe) 클래스를 활용해 데이터베이스에 저장된 HTML을 앵귤러 템플릿에서 안전하게 렌더링하는 방법을 정리했습니다.

X