Some test text!

Discord Logo

Chat with us

PDFTron is now Apryse, learn more here.

Web / Guides / Saving Annotations


PDFTron is now Apryse, learn more here.

Save Annotations in Mendix

After following the getting started guide , you can add an attribute that will store the annotation data that can prepopulate an attribute which can then be passed to the custom widget. The attribute will be a text field for where you want to save annotations . The attribute length must be unlimited.

Adding a custom attribute

Inside of the /CustomWidgets/WebViewer directory, open in it your code editor and change the following files.


Add a new property inside of <propertyGroup caption="General"></propertyGroup>:

<property key="annotationAttribute" type="attribute">
        <attributeType name="String"/>                


Refactor this component to pass all props as mendixProps:

import { Component, ReactNode, createElement } from "react";
import PDFViewer from "./components/PDFViewer";
import { WebViewerContainerProps } from "../typings/WebViewerProps";
import "./ui/WebViewer.css";

export default class WebViewer extends Component<WebViewerContainerProps> {    
    render(): ReactNode {        
        return <PDFViewer mendixProps={this.props} />;    


Refactor this component to pass all props as mendixProps:

import { Component, ReactNode, createElement } from "react";
import PDFViewer from "./components/PDFViewer";
import { WebViewerPreviewProps } from "../typings/WebViewerProps";

declare function require(name: string): string;

export class preview extends Component<WebViewerPreviewProps> {    
    render(): ReactNode {        
        return <PDFViewer mendixProps={this.props}/>;    

export function getPreviewCss(): string {    
    return require("./ui/WebViewer.css");


Refactor this component to handle mendixProps and load the URL that got passed in:

import { createElement, useRef, useEffect, useState } from "react";
import viewer, { Core, WebViewerInstance } from "@pdftron/webviewer";

export interface InputProps {    
    mendixProps: any

const PDFViewer: React.FC<InputProps> = ({ mendixProps }) => {    
    const viewerRef = useRef<HTMLDivElement>(null);    
    const [instance, setInstance] = useState<null | WebViewerInstance>(null);    
    const [annotationManager, setAnnotationManager] = useState<null |Core.AnnotationManager>(null);

    useEffect(() => {        
            path: "/resources/lib",            
        }, viewerRef.current as HTMLDivElement).then(instance => {
            const { documentViewer } = instance.Core;            
    }, []);
    // load document coming from the URL attribute    
    useEffect(() => {        
        if(instance && mendixProps.urlAttribute.value !== '') {
    }    }, [instance, mendixProps.urlAttribute]);

    // save annotation data to the annotation attribute    
    useEffect(() => {        
        const updateAnnotation = async () => {
            if (annotationManager) {
                const xfdf = await annotationManager.exportAnnotations({ links: false, widgets: false });

        if(instance && annotationManager) {            
            instance.UI.setHeaderItems(header => {                
                    type: 'actionButton',                  
                    img: '<svg xmlns="" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"/></svg>',onClick: updateAnnotation                
    }, [instance, annotationManager]);

    return <div className="webviewer" ref={viewerRef}></div>;

export default PDFViewer;

The code snippet above adds a new save button that saves to an annotation attribute passed to the custom widget. Do not forget to run npm run dev on the CustomWidgets/WebViewer directory in your terminal to build it and in Mendix Studio run the command to synchronize project directory under Project/Synchronise Project Directory or hitting F4. After that run the project and try it out.

Get the answers you need: Support