Issue with Signature Field Name Customization in PDF Signing Application

I have developed a PDF signing application using ApryseWebviewer in ReactJS. I implemented a customization feature to allow users to add a signature field name by selecting an option from a dropdown menu.

The issue arises when multiple signature fields are drawn without selecting a name from the dropdown. In such cases, default names are assigned. However, when attempting to change the name of a signature field, the application unexpectedly adds a “Sign Here” text within the field, rendering it unsignable.

Kindly provide a solution to resolve this issue.

Expected Behavior:
Changing the name of a signature field should not add the “Sign Here” text or impact the usability of the field.

Environment Details:

  • Framework: ReactJS
  • PDF Viewer: Webviewer

    (10.4)

Thank you for your support!

1 Like

Hello Ajay,

Thank you for contacting WebViewer Forums.

The “sign here” element generally gets shown when exiting out of form builder mode which it looks to be from the video provided. This can be seen since the form toolbar is also exited. Please check your code if this is applied.

Regards,
Luke

1 Like

Hi Luke,

Thank you for your response.

I’ve reviewed my code and confirmed that I haven’t implemented any functionality that exits the form toolbar.

import WebViewer from '@pdftron/webviewer'
import { useEffect, useMemo, useRef } from 'react'

import { documentEventLog } from 'modules/document-event-log'
import { useCreateDocumentEventLogMutation } from 'modules/document-event-log/document-event-log-api'
import { useLazyGetSettingQuery } from 'modules/settings/settings-api'
import { useSetDocumentViewer } from 'pages/Authentication/profile/components/workflow/document-viewer-provider'
import {
	ACTIONS,
	roundToDecimal,
} from 'pages/Authentication/profile/components/workflow/documents-tab'
import notification from 'utilities/notification'
import { signatureViewDisabledElement } from '.'

const SignatureTab = ({ formik, documentId }) => {
	const viewerRef = useRef(null)
	const formValues = useMemo(() => formik?.values, [formik?.values])
	const [createDocumentEventLog] = useCreateDocumentEventLogMutation()
	const FILE_URL = useMemo(() => formValues?.file_path, [formValues?.file_path])
	const no_of_users = useMemo(() => formValues?.min_clients?.value || 0, [formValues])
	const [getSetting] = useLazyGetSettingQuery()
	const setDocumentViewer = useSetDocumentViewer()

	const createInstance = async () => {
		const response = await getSetting('pdf_tron_apikey')
		const settingValue = response?.data?.setting
		try {
			if (settingValue?.status === 200 && settingValue?.data?.setting_value) {
				const instance = await WebViewer(
					{
						path: '/lib',
						initialDoc: FILE_URL,
						fullAPI: true,
						disabledElements: signatureViewDisabledElement,
						custom: JSON.stringify({ total_users: no_of_users }),
						licenseKey: settingValue?.data?.setting_value,
					},
					viewerRef.current,
				)

				return instance
			}
		} catch (error) {
			notification(error)
		}
	}

	useEffect(() => {
		if (FILE_URL) {
			createInstance().then((instance) => {
				if (instance?.Core) {
					if (documentId) {
						createDocumentEventLog({
							document_id: documentId,
							event_type: documentEventLog.eventTypes.SignatureFieldCreation,
							module_type: documentEventLog.moduleTypes.DocumentTemplateCreation,
						})
					}

					const { annotationManager, Annotations, documentViewer } = instance.Core
					const { WidgetFlags, Forms, TextWidgetAnnotation, Border, Color } = Annotations
					instance.UI.enableFeatures([instance.UI.Feature.Initials])

					const formFieldCreationManager = annotationManager.getFormFieldCreationManager()
					formFieldCreationManager.startFormFieldCreationMode()

					documentViewer.addEventListener('documentLoaded', () => {
						documentViewer.getAnnotationsLoadedPromise().then(() => {
							annotationManager.addEventListener('annotationChanged', () => {
								setDocumentViewer(instance)
							})
						})
					})

					// start timestamp field insertion with signature field
					annotationManager.addEventListener(
						'annotationChanged',
						(annotations, action, { imported }) => {
							if (imported) {
								return
							}

							const selectedAnnotation = annotations[0]

							// add timestamp annotation here on signature field insertion
							if (
								selectedAnnotation instanceof
									Annotations.SignatureWidgetAnnotation &&
								action === ACTIONS.ADD
							) {
								const fieldName = selectedAnnotation.fieldName

								const [$fieldName, $userRole] = fieldName.split('.')

								const timestampFieldName = [
									$fieldName,
									$userRole,
									'timestamp',
								].join('.')
								// start insertion of timestamp form textfield
								const timestampWidgetflags = new WidgetFlags()

								const field = new Forms.Field(timestampFieldName, {
									type: 'Tx',
									defaultValue: 'timestamp goes here',
									flags: timestampWidgetflags,
								})

								const border = new Border()
								border.color = new Color(0, 0, 0)
								border.width = 1

								const widgetAnnot = new TextWidgetAnnotation(field)
								widgetAnnot.PageNumber = selectedAnnotation.PageNumber
								widgetAnnot.X = selectedAnnotation.X
								widgetAnnot.Y =
									selectedAnnotation.Y +
									roundToDecimal(selectedAnnotation.Height, 2)
								widgetAnnot.Width = 140
								widgetAnnot.Height = 15
								widgetAnnot.border = border

								annotationManager.getFieldManager().addField(field)
								annotationManager.addAnnotation(widgetAnnot)
								annotationManager.drawAnnotationsFromList([widgetAnnot])
								// end insertion of timestamp form textfield
							}

							setDocumentViewer(instance)
						},
					)
					// end timestamp field insertion with signature field
				}
			})
		}
	}, [FILE_URL, documentId])

	return (
		<div>
			<h3 className='mb-2 text-lg font-bold'>Signature</h3>
			<p className='text-gray-600'>Signature mapping</p>

			<div className='signature_div_height rounded-md bg-white p-6'>
				<p>In this step you can add signature field to the pdf.</p>
				<div
					className='webviewer signature_height'
					ref={viewerRef}
					style={{ height: '100vh' }}
				/>
			</div>
		</div>
	)
}

export default SignatureTab

Best regards,
Ajay Kumar

1 Like

Hello Ajay,

Thank you for your reply.

It seems that every time the field name is changed, the following code block gets triggered and is storing the instance with every call. Is there a reason for the setDocumentViewer(instance) line?

annotationManager.addEventListener('annotationChanged', (annotations, action, { imported }) => {
...
setDocumentViewer(instance)
})

Regards,
Luke

1 Like

Hi Luke,

I’m saving the document instance so it can be accessed in another component. This process allows me to obtain the signed PDF, which I then need to save.

Please let me know if you need further details.

Best regards,
Ajay Kumar

1 Like

Hi Luke,

Do you have any solution for this?

1 Like

Hello Ajay,

Thank you for your reply.

It is quite difficult to reproduce and identify the issue without a working sample project as I do not have access to the dependencies defined. Are you able to provide a minified project using one of our samples here? ApryseSDK repositories · GitHub

Regards,
Luke

1 Like

Hi Luke,

I’ve created a GitHub repository for the signing app, including only the signature field insertion part. Please review it to explore a better solution.

Best regards,
Ajay Kumar

1 Like

Hi Luke,

Is there any update for me?

1 Like

Hello Ajay,

Thank you for your reply.

I checked with your application and I can see that the dropdown values were injected into the minified code. This is not recommended to add a value there and then reference the object in the Javascript. This is causing issues where the field names are incorrect and the form creation mode gets abruptly ended and changes the ribbon group to the “View” mode. In “View” mode is the only time the “sign here” element can be seen.

You can check the status of form builder mode with isInFormFieldCreationMode()

Regards,
Luke

1 Like

Hi Luke,

Thanks for your response,

  1. I have customized the field names as outlined in the “Advanced UI Customization” section of the documentation.

  2. I have also make sure to check the status of form builder mode with isInFormFieldCreationMode()

It still remains the same.

1 Like

Hello Ajay,

Thank you for your reply.

I would check the ‘annotationChanged’ code block as that seems to be causing the issue. Removing the code block removes any of the issues initially.

If you console.log(annotations, action) when selecting the field name after the field has been placed, it returns a number of actions which indicate that the form field creation mode is ended (delete) then started again (add). The modify actions are also affecting every widget on the form as well:

Regards,
Luke

1 Like