플랫폼별 통합
Angular
Angular에서는 ViewChild로 컨테이너를 잡고 ngAfterViewInit에서 마운트, ngOnDestroy에서 정리합니다.
공통 전제
뷰어 산출물이 /pdfv/ 경로에 배포되어 있어야 합니다 — 시작하기 참고.
SDK는 src/index.html에 <script src="/pdfv/sdk/pdfv-sdk.js">로 로드하고,
개발 중에는 proxy.conf.json으로 /pdfv를 운영 서버에 프록시하세요.
컴포넌트 예제
pdf-editor.component.ts ts
import {
Component, ElementRef, ViewChild,
AfterViewInit, OnDestroy, Input,
} from '@angular/core';
// 전역 SDK 선언 (src/typings.d.ts 등에 두어도 됩니다)
declare const Inko: any;
@Component({
selector: 'app-pdf-editor',
standalone: true,
template: `<div #container style="width:100%; height:80vh"></div>`,
})
export class PdfEditorComponent implements AfterViewInit, OnDestroy {
@Input() docId!: number;
@Input() pdfUrl!: string;
@Input() initialCanvasData?: string;
@ViewChild('container', { static: true })
container!: ElementRef<HTMLDivElement>;
private viewer: any;
ngAfterViewInit(): void {
this.viewer = Inko.mount(this.container.nativeElement, {
src: '/pdfv/index.html',
pdfUrl: this.pdfUrl,
initialCanvasData: this.initialCanvasData,
onSave: (canvasData: string, ok: boolean) => {
if (!ok) return;
fetch('/api/annotations', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ docId: this.docId, canvasData }),
});
},
});
}
// 외부 버튼에서 호출할 수 있게 노출
save(): void {
this.viewer?.save();
}
ngOnDestroy(): void {
this.viewer?.destroy();
}
}declare const Inko: any;선언으로 전역 SDK를 타입 오류 없이 사용합니다. 프로젝트 공용typings.d.ts에 두면 모든 컴포넌트에서 재사용됩니다.standalone: true는 Angular 14+ 기준이며, NgModule 방식이라면 선언만 모듈로 옮기면 됩니다.
HttpClient와 Zone
예제의 fetch는 Zone과 무관하게 동작합니다. Angular의 HttpClient를 쓰고
콜백 결과로 화면 상태를 갱신한다면, SDK 콜백이 Angular Zone 밖에서 호출될 수 있으므로 NgZone.run()으로 감싸 변경 감지를 보장하세요.
HttpClient 사용 시 ts
// Angular 스타일로 HttpClient를 쓰려면 — NgZone 밖 콜백에서 재진입
import { HttpClient } from '@angular/common/http';
import { NgZone } from '@angular/core';
constructor(private http: HttpClient, private zone: NgZone) {}
// onSave 콜백 안에서:
onSave: (canvasData: string, ok: boolean) => {
if (!ok) return;
// SDK 콜백은 Angular Zone 밖에서 올 수 있으므로 zone.run으로 감쌉니다
this.zone.run(() => {
this.http.post('/api/annotations', {
docId: this.docId,
canvasData,
}).subscribe();
});
}주의사항
- destroy() 필수 —
ngOnDestroy에서 호출하지 않으면 라우팅마다 iframe·리스너가 누적됩니다. - SSR(Angular Universal) — 서버 렌더 단계에는
window가 없으므로 브라우저에서만 실행되도록isPlatformBrowser가드를 두세요. - 문서 교체 —
@Input변경으로 재마운트하는 대신this.viewer.loadPdfUrl()을 호출하면 인스턴스를 유지한 채 문서만 바뀝니다.