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.

WebViewer.xml

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

XML

1<property key="annotationAttribute" type="attribute">
2 <caption>Annotation</caption>
3 <description/>
4 <attributeTypes>
5 <attributeType name="String"/>
6 </attributeTypes>
7</property>

WebViewer.tsx

Refactor this component to pass all props as mendixProps:

JavaScript

1import { Component, ReactNode, createElement } from "react";
2import PDFViewer from "./components/PDFViewer";
3import { WebViewerContainerProps } from "../typings/WebViewerProps";
4import "./ui/WebViewer.css";
5
6export default class WebViewer extends Component<WebViewerContainerProps> {
7 render(): ReactNode {
8 return <PDFViewer mendixProps={this.props} />;
9 }
10}

WebViewer.editorPreview.tsx

Refactor this component to pass all props as mendixProps:

JavaScript

1import { Component, ReactNode, createElement } from "react";
2import PDFViewer from "./components/PDFViewer";
3import { WebViewerPreviewProps } from "../typings/WebViewerProps";
4
5declare function require(name: string): string;
6
7export class preview extends Component<WebViewerPreviewProps> {
8 render(): ReactNode {
9 return <PDFViewer mendixProps={this.props}/>;
10 }
11}
12
13export function getPreviewCss(): string {
14 return require("./ui/WebViewer.css");
15}

Components/PDFViewer.tsx

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

1import { createElement, useRef, useEffect, useState } from "react";
2import viewer, { Core, WebViewerInstance } from "@pdftron/webviewer";
3
4export interface InputProps {
5 mendixProps: any
6}
7
8const PDFViewer: React.FC<InputProps> = ({ mendixProps }) => {
9 const viewerRef = useRef<HTMLDivElement>(null);
10 const [instance, setInstance] = useState<null | WebViewerInstance>(null);
11 const [annotationManager, setAnnotationManager] = useState<null |Core.AnnotationManager>(null);
12
13 useEffect(() => {
14 viewer({
15 path: "/resources/lib",
16 }, viewerRef.current as HTMLDivElement).then(instance => {
17 const { documentViewer } = instance.Core;
18 setInstance(instance);
19 setAnnotationManager(documentViewer.getAnnotationManager());
20 });
21 }, []);
22
23 // load document coming from the URL attribute
24 useEffect(() => {
25 if(instance && mendixProps.urlAttribute.value !== '') {
26 instance.UI.loadDocument(mendixProps.urlAttribute.value);
27 } }, [instance, mendixProps.urlAttribute]);
28
29 // save annotation data to the annotation attribute
30 useEffect(() => {
31 const updateAnnotation = async () => {
32 if (annotationManager) {
33 const xfdf = await annotationManager.exportAnnotations({ links: false, widgets: false });
34 mendixProps.annotationAttribute.setValue(xfdf);
35 }
36 }
37
38 if(instance && annotationManager) {
39 instance.UI.setHeaderItems(header => {
40 header.push({
41 type: 'actionButton',
42 img: '<svg xmlns="http://www.w3.org/2000/svg" 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
43 });
44 });
45 }
46 }, [instance, annotationManager]);
47
48 return <div className="webviewer" ref={viewerRef}></div>;
49};
50
51export 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.

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales