Activate SignatureWidgetAnnotation programmatically

Which product are you using?
PDF.js Express Plus

PDF.js Express Version
UI version: 8.4.1
Core version: 8.4.0
Build: NC8xMi8yMDIyfGI0OTc1YjFjZA==
WebViewer Server: false
Full API: false

Detailed description
How can I activate the SignatureWidgetAnnotation programmatically?

I would like to programmatically activate as if I were mouse-clicking the SignatureWidgetAnnotation.

I’ve tried something like this and it didn’t work:

const annots = annotationManager.getAnnotationsList().filter(
    (annot: any) => annot instanceof Annotations.SignatureWidgetAnnotation,
);
annots[0].innerElement.click();

// or

const clickEvent = new Event('click');
annots[0].innerElement.dispatchEvent(clickEvent); // or with annots[0].firstChild, annots[0].firstChild.firstChild, ...

Thanks in advance!

Hello, I’m Ron, an automated tech support bot :robot:

While you wait for one of our customer support representatives to get back to you, please check out some of these documentation pages:

Guides:APIs:Forums:

Hello vicente,

What do you mean by ‘activate’ the SignatureWidgetAnnotation?
If you are trying to open the signature modal, you can do so like:

instance.UI.openElement('signatureModal')

Let me know if this works for you

Best regards,
Tyler Gordon
Web Development Support Engineer
PDFTron

Hello Tyler,

I would like to open the signature modal, but associated with the SignatureWidgetAnnotation that is already in the document, as if I were clicking the SignatureWidgetAnnotation with the mouse.

When I use “instance.UI.openElement('signatureModal')”, a new Annotation is created without being associated with the pre-existing SignatureWidgetAnnotation.

So ‘activate’ would open the corresponding signatureModal of the SignatureWidgetAnnotation.

Programmatically simulate this click on “Sign here”:

Thanks,
Vicente.

Hello vicente,

Thank you for clarifying, this currently isn’t doable by just calling .click() on the element, however you could customize the Sign Here inner element to handle this using: PDFTron WebViewer Namespace: Annotations
Let me know if that works for you!

Best regards,
Tyler Gordon
Web Development Support Engineer
PDFTron

Hello Tyler,

Thanks for the reply!

I already customize it using Annotations.SignatureWidgetAnnotation.prototype.createSignHereElement, but I basically do it for styling and text. How could I customize it for this purpose?

I saw that the setCustomCreateSignHereElementHandler would give access to the Annotation, SignHereElement and Tool, but I already had access to them and didn’t know what to do.

Thanks,
Vicente!

Hello vicente,

Looking deeper into the backend of the code, it seems the modal is opened when the “locationSelected” event is triggered on the SignatureCreateTool. This means you can trigger it like so:

const signatureTool = documentViewer.getTool('AnnotationCreateSignature')
    const signatureAnnotation = annotationManager.getAnnotationsList().filter( (annot) => annot instanceof Annotations.SignatureWidgetAnnotation);

    signatureTool.addEventListener('locationSelected', ()=>{
      console.log('triggered') // to double check the locationSelected event has been triggered
    })
    signatureTool.trigger(
      'locationSelected', 
      [
        {
          x: signatureAnnotation[0].getX(), 
          y: signatureAnnotation[0].getY()
        }, // this object being the pageCoordinates for the signature widget
        signatureAnnotation[0] // the signature widget itself
      ]
    )

Here are some links to the APIs used:

Let me know if this works for you!

Best regards,
Tyler Gordon
Web Development Support Engineer
PDFTron

Hello, Tyler!

The trigger signatureTool.trigger('locationSelected', ...) is really opening the modal, unfortunately still not binding to the corresponding widget, but mainly not editing the signature location.

When I call the signatureTool.hasLocation() function, it returns false.

So when I try to call signatureTool.addSignature(), I get the error: TypeError: this.location is null;

I tried to do something like this:

signatureTool.addEventListener(
  'locationSelected',
  (pageCoordinates: any, annotation: any) => {
    console.log('hasLocation', signatureTool.hasLocation());
  },
);

signatureTool.addEventListener('signatureSaved', (annotations: any) => {
  signatureTool.setSignature(annotations[0]);
  signatureTool.addSignature();
});

signatureTool.trigger('locationSelected', [
  {
    pageNumber: signatureWidgetAnnotations[0].getPageNumber(),
    x: signatureWidgetAnnotations[0].getX(),
    y: signatureWidgetAnnotations[0].getY(),
  }, 
  signatureWidgetAnnotations[0],
]);

Look how is the flow:

activate_signature_widget

Thanks,
Vicente.

Hello Vincente,

Whats needed before doing addSignature() is the .location of the tool, you could set the location of the tool to signature widget you are signing like so:

    signatureTool.addEventListener('signatureSaved', (annotations) => {
      signatureTool.setSignature(annotations[0]);
      signatureTool.location = {
        x: signatureAnnotation[0].getX(), 
        y: signatureAnnotation[0].getY(), 
        pageNumber: signatureAnnotation[0].PageNumber
      }
      signatureTool.addSignature();
    });

Best regards,
Tyler Gordon
Web Development Support Engineer
PDFTron

Hello, Tyler!

Yes, that worked for me, but it’s still not binding the annotation to the widget. See in the gif I sent earlier that the annotation and the widget are at the same time in the document.

I’ve already tried looking for some property of the signatureTool in the documentation like the .location, but I couldn’t find it. I tried this link that has the types, but I didn’t find it either.

Is there any easy way to do this? So that when I delete the annotation, the widget reappears.

In the same way as in the normal flow:

normal_flow_signature

Thanks,
Vicente.

Hello Vicente,

You can set the associated annotation to the widget with: setAssociatedSignatureAnnotation()
I was able create the behaviour here:

documentViewer.addEventListener('annotationsLoaded', ()=>{
    const signatureTool = documentViewer.getTool('AnnotationCreateSignature')
    const signatureAnnotation = annotationManager.getAnnotationsList().filter( (annot) => annot instanceof Annotations.SignatureWidgetAnnotation);

    signatureTool.addEventListener(
      'locationSelected',
      (pageCoordinates, annotation) => {
        console.log('hasLocation', signatureTool.hasLocation());
      },
    );

    signatureTool.addEventListener('signatureSaved', async (annotations) => {
      signatureTool.setSignature(annotations[0]);
      signatureTool.location = {
        x: signatureAnnotation[0].getX(), 
        y: signatureAnnotation[0].getY(), 
        pageNumber: signatureAnnotation[0].PageNumber
      }
      // set the associated signature annotation to the signature widget annotation
      signatureAnnotation[0].setAssociatedSignatureAnnotation(annotations[0])
      signatureTool.addSignature();
    });

    annotationManager.addEventListener('annotationChanged', (annotations, action) => {
      if(action == 'delete') {
        // check if the annotation that was removed was a signature
        if(annotations[0].Subject == "Signature") {
          // remove set the associated Signature annotation to null, **this sill show the 'Sign here' element**
          signatureAnnotation[0].setAssociatedSignatureAnnotation(null);
        }
      }
    })

    signatureTool.trigger(
      'locationSelected', 
      [
        {
          x: signatureAnnotation[0].getX(), 
          y: signatureAnnotation[0].getY()
        }, 
        signatureAnnotation[0]
      ]
    )
  })```

Let me know if this works for you,

Best regards,
Tyler Gordon
Web Development Support Engineer
PDFTron

Hello, Tyler!

No, unfortunately it didn’t work for me. In fact, when I use signatureAnnotation[0].setAssociatedSignatureAnnotation(null) and delete the annotation manually, the widget is still styled display none. Even if I follow the normal flow of clicking the widget

I noticed that the default behavior of PDF.js Express is to delete the annotation of the document but still remain associated with the widget. That is, even after deleting the annotation and calling getAssociatedSignatureAnnotation(), the annotation will still be there, it will not be null.

Thanks,
Vicente!

Hello vicente,

Can you try this code snippet?

  const signWidget = () => {
    const signatureWidget = annotationManager.getAnnotationsList()
      .find(annotation => annotation instanceof Annotations.SignatureWidgetAnnotation);

    const signatureTool = documentViewer.getTool('AnnotationCreateSignature')
    signatureTool.addEventListener('signatureReady', async (annotation) => {
      let signatureWidgetRect = signatureWidget.getRect();
      // Get min scale to fit the signature widget
      const hScale = signatureWidgetRect.getHeight() / annotation['Height'];
      const wScale = signatureWidgetRect.getWidth() / annotation['Width'];
      const scale = Math.min(hScale, wScale);
      const resizeRect = new Core.Math.Rect(
        signatureWidgetRect['x1'],
        signatureWidgetRect['y1'],
        signatureWidgetRect['x1'] + annotation['Width'] * scale,
        signatureWidgetRect['y1'] + annotation['Height'] * scale,
      );

      annotation.resize(resizeRect); 
      signatureWidget.setAssociatedSignatureAnnotation(annotation)
    });

    signatureTool.location = {
      x: signatureWidget.getX(), 
      y: signatureWidget.getY(), 
      pageNumber: signatureWidget.PageNumber
    }

    signatureTool.trigger(
      'locationSelected',
      {
        pageNumber: signatureWidget.PageNumber,
        x: signatureWidget.X,
        y: signatureWidget.Y,
      },
      signatureWidget
    )
  }

I think there was a logic error in the one I sent prior

Best regards
Tyler Gordon
Web Development Support Engineer
PDFTron

1 Like

Hello, Tyler!

The code snippet helped me a lot. Thank you so much! I was also needing to resize the annotation and now I can.

But it still doesn’t work like the normal flow of clicking the widget. For that, I did two more things:

  1. I hid the widget after adding the annotation
signatureTool.addEventListener('signatureReady', async (annotation) => {
   ... // your code here
   signatureWidget.innerElement.style.display = 'none';
});
  1. Listen for the delete annotation event and shows the widget again
annotationManager.addEventListener(
   'annotationChanged',
   (annotations, action) => { 
      if (action === 'delete') {
         const signatureWidget = annotationManager
            .getAnnotationsList()
            .find( (annot) =>
               annot instanceof Annotations.SignatureWidgetAnnotation &&
               annot.getAssociatedSignatureAnnotation()?.Id === annotations[0].Id);

         signatureWidget.innerElement.style.display = 'block';
      }
   },
);

I believe the problem is now resolved.
Thanks a lot again, it helped me a lot to get to know PDF.js Express better.

Best regards,
Vicente!