> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/salesforce/events/annotation-events.md).

# Adding annotation events

Learn how to optimize your annotations with events in AnnotationManager. Hook into annotationChanged, annotationSelected, and more for enhanced functionality. Click to explore further! Salesforce WebV

There are a number of events related to annotations that can be useful to hook into. To do this you'll add a listener to the `AnnotationManager`.

{% hint style="warning" %}
**Do not add the listener in the documentLoaded event**

This will cause a new listener to be attached every time a new document is loaded
{% endhint %}

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { documentViewer, annotationManager } = instance.Core;

    annotationManager.addEventListener('annotationChanged', () => {
      // ...
    });
  });
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [Core](https://sdk.apryse.com/api/web/Core.html) [AnnotationManager#annotationChanged](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationChanged__anchor)
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { docViewer, annotManager } = instance;

    annotManager.on('annotationChanged', () => {
      // ...
    });
  });
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [AnnotationManager#annotationChanged](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationChanged__anchor)
{% endtab %}
{% endtabs %}

## annotationChanged (add/modify/delete)

The [annotationChanged](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationChanged__anchor) event is fired every time an annotation is added, modified or deleted. The handler takes three parameters; the event object, an array of annotations that have changed and a string for the action (add, modify, delete).

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { annotationManager } = instance.Core;
    annotationManager.addEventListener('annotationChanged', (annotations, action) => {
      if (action === 'add') {
        console.log('this is a change that added annotations');
      } else if (action === 'modify') {
        console.log('this change modified annotations');
      } else if (action === 'delete') {
        console.log('there were annotations deleted');
      }

      annotations.forEach((annot) => {
        console.log('annotation page number', annot.PageNumber);
      });
    });
  })
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [Core](https://sdk.apryse.com/api/web/Core.html) [AnnotationManager#annotationChanged](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationChanged__anchor)
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { annotManager } = instance;
    annotManager.on('annotationChanged', (annotations, action) => {
      if (action === 'add') {
        console.log('this is a change that added annotations');
      } else if (action === 'modify') {
        console.log('this change modified annotations');
      } else if (action === 'delete') {
        console.log('there were annotations deleted');
      }

      annotations.forEach((annot) => {
        console.log('annotation page number', annot.PageNumber);
      });
    });
  })
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [AnnotationManager#annotationChanged](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationChanged__anchor)
{% endtab %}
{% endtabs %}

{% hint style="info" %}
The annotationChanged event will also be fired whenever annotations are imported from your server or inside the document, that is, they weren't created directly by a user.
{% endhint %}

If you want to do something different in that case, maybe ignore those events, you can use the `imported` property of the event object. For example:

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { annotationManager } = instance.Core;
    annotationManager.addEventListener('annotationChanged', (annotations, action, { imported }) => {
      if (imported) {
        return;
      }
      // do event handling
    });
  })
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [AnnotationManager#annotationChanged](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationChanged__anchor) [AnnotationChangedInfoObject](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#.AnnotationChangedInfoObject__anchor)
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { annotManager } = instance;
    annotManager.on('annotationChanged', (annotations, action, { imported, isUndoRedo }) => {
      if (imported) {
        return;
      }
      // do event handling
    });
  })
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [AnnotationManager#annotationChanged](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationChanged__anchor) [AnnotationChangedInfoObject](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#.AnnotationChangedInfoObject__anchor)
{% endtab %}
{% endtabs %}

One other property you might want to utilize is `isUndoRedo` which will return true if the annotation has changed as a result of an undo or redo action.

## annotationSelected

The [annotationSelected](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationSelected__anchor) event is fired any time an annotation is selected or deselected in the UI. The parameters are similar to annotationChanged; there is an event object, array of annotations and a string for the action (selected or deselected). If all annotations have been deselected then the annotations array will be null.

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { annotationManager } = instance.Core;
    annotationManager.addEventListener('annotationSelected', (annotations, action) => {
      if (action === 'selected') {
        console.log('annotation selection');
      } else if (action === 'deselected') {
        console.log('annotation deselection');
      }

      console.log('annotation list', annotations);

      if (annotations === null && action === 'deselected') {
        console.log('all annotations deselected');
      }
    });
  })
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [Core](https://sdk.apryse.com/api/web/Core.html) [AnnotationManager#annotationSelected](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationSelected__anchor)
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { annotManager } = instance;
    annotManager.on('annotationSelected', (annotations, action) => {
      if (action === 'selected') {
        console.log('annotation selection');
      } else if (action === 'deselected') {
        console.log('annotation deselection');
      }

      console.log('annotation list', annotations);

      if (annotations === null && action === 'deselected') {
        console.log('all annotations deselected');
      }
    });
  })
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [AnnotationManager#annotationSelected](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#event:annotationSelected__anchor)
{% endtab %}
{% endtabs %}

Annotations can be selected from the UI by clicking on them and once selected there will be a dashed border drawn around them. To programmatically select/deselect annotations you can use the selectAnnotation(s) and deselectAnnotation(s) functions. The getSelectedAnnotations will tell you which annotations are currently selected. For example, the following code deselects one of the currently selected annotations:

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { annotationManager } = instance.Core;
    const selectedAnnots = annotationManager.getSelectedAnnotations();

    if (selectedAnnots.length > 0) {
      const firstSelectedAnnot = selectedAnnots[0];
      annotManager.deselectAnnotation(firstSelectedAnnot);
    }
  });
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [Core](https://sdk.apryse.com/api/web/Core.html) [AnnotationManager.getSelectedAnnotations](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#getSelectedAnnotations__anchor) [AnnotationManager.deselectAnnotation](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#deselectAnnotation__anchor)
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { annotManager } = instance;
    const selectedAnnots = annotManager.getSelectedAnnotations();

    if (selectedAnnots.length > 0) {
      const firstSelectedAnnot = selectedAnnots[0];
      annotManager.deselectAnnotation(firstSelectedAnnot);
    }
  });
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [AnnotationManager.getSelectedAnnotations](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#getSelectedAnnotations__anchor) [AnnotationManager.deselectAnnotation](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#deselectAnnotation__anchor)
{% endtab %}
{% endtabs %}

There are several more [events on AnnotationManager](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#toc64__anchor) that may be useful to you.

## annotationsLoaded

The [annotationsLoaded](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#event:annotationsLoaded__anchor) event is fired when all the annotations internal to the document have been loaded. Since DocumentViewer is managing this process the event is fired on DocumentViewer.

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { documentViewer, annotationManager } = instance.Core;
    documentViewer.addEventListener('annotationsLoaded', () => {
      // all annotations are available
      const annotations = annotationManager.getAnnotationsList();
    });
  })
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [Core](https://sdk.apryse.com/api/web/Core.html) [AnnotationManager.getAnnotationsList](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#getAnnotationsList__anchor) [AnnotationManager#annotationsLoaded](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#event:annotationsLoaded__anchor)
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(instance => {
    const { docViewer, annotManager } = instance;
    docViewer.on('annotationsLoaded', () => {
      // all annotations are available
      const annotations = annotManager.getAnnotationsList();
    });
  })
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [AnnotationManager.getAnnotationsList](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#getAnnotationsList__anchor) [AnnotationManager#annotationsLoaded](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#event:annotationsLoaded__anchor)
{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.apryse.com/salesforce/events/annotation-events.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
